From fdcfc8a2534cbc044df639ac99bb7edae177429e Mon Sep 17 00:00:00 2001 From: JFH <20402845+jfhenon@users.noreply.github.com> Date: Tue, 28 Dec 2021 11:02:29 -0300 Subject: [PATCH] move to standard linter for simpler configuration --- .eslintignore | 30 - .eslintrc.js | 96 - .gitignore | 1 - .npmignore | 1 - cypress/integration/ui/clipboard.js | 68 +- cypress/integration/ui/control-points.js | 26 +- cypress/integration/ui/export.js | 22 +- cypress/integration/ui/issues/issue-359.js | 20 +- cypress/integration/ui/issues/issue-407.js | 26 +- cypress/integration/ui/issues/issue-408.js | 22 +- cypress/integration/ui/issues/issue-423.js | 20 +- cypress/integration/ui/issues/issue-660.js | 26 +- cypress/integration/ui/key-commands.js | 12 +- cypress/integration/ui/scenario.js | 222 +- cypress/integration/ui/scenario1.js | 48 +- cypress/integration/ui/scenario2.js | 136 +- cypress/integration/ui/scenario3.js | 82 +- cypress/integration/ui/scenario4.js | 190 +- cypress/integration/ui/scenario5.js | 174 +- cypress/integration/ui/scenario6.js | 162 +- cypress/integration/ui/scenario7.js | 162 +- cypress/integration/ui/tool-selection.js | 14 +- .../browser-bugs/removeItem-setAttribute.js | 14 +- cypress/integration/unit/contextmenu.js | 46 +- cypress/integration/unit/coords.js | 336 +- cypress/integration/unit/draw.js | 958 ++-- cypress/integration/unit/history.js | 719 +-- cypress/integration/unit/math.js | 156 +- cypress/integration/unit/path.js | 242 +- cypress/integration/unit/recalculate.js | 173 +- cypress/integration/unit/sanitize.js | 22 +- cypress/integration/unit/select.js | 146 +- cypress/integration/unit/test1.js | 212 +- cypress/integration/unit/units.js | 120 +- cypress/integration/unit/utilities-bbox.js | 573 +-- .../integration/unit/utilities-performance.js | 172 +- cypress/integration/unit/utilities.js | 346 +- cypress/plugins/index.js | 8 +- cypress/plugins/main.js | 36 +- cypress/support/assert-almostEquals.js | 16 +- cypress/support/assert-close.js | 66 +- .../assert-expectOutOfBoundsException.js | 22 +- cypress/support/assertion-wrapper.js | 12 +- cypress/support/commands.js | 18 +- cypress/support/index.js | 8 +- cypress/support/ui-test-helper.js | 28 +- demos/canvas.html | 39 +- docs/jsdoc-config.js | 6 +- docs/tutorials/ConfigOptions.md | 16 +- docs/tutorials/Events.md | 10 +- docs/tutorials/ExtensionDocs.md | 16 +- docs/versions/3.0.0.md | 2 +- nyc.config.js | 18 +- package-lock.json | 4403 ++++++++--------- package.json | 58 +- rollup.config.js | 86 +- src/common/browser.js | 52 +- src/common/units.js | 144 +- src/editor/ConfigObj.js | 166 +- src/editor/Editor.js | 862 ++-- src/editor/EditorStartup.js | 704 ++- src/editor/MainMenu.js | 315 +- src/editor/Rulers.js | 229 +- src/editor/browser-not-supported.js | 8 +- src/editor/components/PaintBox.js | 151 +- src/editor/components/index.js | 29 +- .../components/jgraduate/ColorValuePicker.js | 552 +-- src/editor/components/jgraduate/Slider.js | 326 +- src/editor/components/jgraduate/Util.js | 165 +- .../components/jgraduate/jQuery.jGraduate.js | 1132 +++-- .../components/jgraduate/jQuery.jPicker.js | 1828 +++---- src/editor/components/jgraduate/paint.js | 78 +- src/editor/components/seButton.js | 148 +- src/editor/components/seColorPicker.js | 131 +- src/editor/components/seDropdown.js | 94 +- src/editor/components/seExplorerButton.js | 226 +- src/editor/components/seFlyingButton.js | 189 +- src/editor/components/seInput.js | 112 +- src/editor/components/seList.js | 135 +- src/editor/components/seListItem.js | 87 +- src/editor/components/seMenu.js | 63 +- src/editor/components/seMenuItem.js | 84 +- src/editor/components/sePalette.js | 67 +- src/editor/components/sePlainBorderButton.js | 14 +- src/editor/components/sePlainMenuButton.js | 10 +- src/editor/components/seSelect.js | 155 +- src/editor/components/seSpinInput.js | 162 +- src/editor/components/seText.js | 76 +- src/editor/components/seZoom.js | 96 +- src/editor/contextmenu.js | 38 +- src/editor/dialogs/SePlainAlertDialog.js | 18 +- src/editor/dialogs/cmenuDialog.js | 290 +- src/editor/dialogs/cmenuLayersDialog.js | 153 +- src/editor/dialogs/editorPreferencesDialog.js | 426 +- src/editor/dialogs/exportDialog.js | 143 +- src/editor/dialogs/imagePropertiesDialog.js | 401 +- src/editor/dialogs/index.js | 22 +- .../dialogs/se-elix/define/NumberSpinBox.js | 5 +- .../dialogs/se-elix/src/base/NumberSpinBox.js | 93 +- .../se-elix/src/plain/PlainNumberSpinBox.js | 6 +- src/editor/dialogs/seAlertDialog.js | 14 +- src/editor/dialogs/seConfirmDialog.js | 18 +- src/editor/dialogs/sePromptDialog.js | 62 +- src/editor/dialogs/seSelectDialog.js | 18 +- src/editor/dialogs/svgSourceDialog.js | 191 +- .../ext-eyedropper/ext-eyedropper.js | 138 +- .../extensions/ext-eyedropper/locale/en.js | 2 +- .../extensions/ext-eyedropper/locale/fr.js | 2 +- .../extensions/ext-eyedropper/locale/zh-CN.js | 2 +- src/editor/extensions/ext-grid/ext-grid.js | 177 +- src/editor/extensions/ext-grid/locale/en.js | 2 +- src/editor/extensions/ext-grid/locale/fr.js | 2 +- .../extensions/ext-grid/locale/zh-CN.js | 2 +- .../ext-helloworld/ext-helloworld.js | 60 +- .../extensions/ext-helloworld/locale/en.js | 2 +- .../extensions/ext-helloworld/locale/fr.js | 2 +- .../extensions/ext-helloworld/locale/zh-CN.js | 2 +- .../extensions/ext-imagelib/ext-imagelib.js | 626 ++- src/editor/extensions/ext-imagelib/index.js | 54 +- .../extensions/ext-imagelib/locale/de.js | 2 +- .../extensions/ext-imagelib/locale/en.js | 2 +- .../extensions/ext-imagelib/locale/fr.js | 2 +- .../extensions/ext-imagelib/locale/pl.js | 2 +- .../extensions/ext-imagelib/locale/pt-BR.js | 2 +- .../extensions/ext-imagelib/locale/ro.js | 2 +- .../extensions/ext-imagelib/locale/sk.js | 2 +- .../extensions/ext-imagelib/locale/sl.js | 2 +- .../extensions/ext-imagelib/locale/zh-CN.js | 2 +- .../extensions/ext-imagelib/openclipart.js | 457 +- .../extensions/ext-markers/ext-markers.js | 287 +- .../extensions/ext-markers/locale/en.js | 2 +- .../extensions/ext-markers/locale/zh-CN.js | 2 +- .../extensions/ext-opensave/ext-opensave.js | 263 +- .../extensions/ext-opensave/locale/en.js | 2 +- .../extensions/ext-opensave/locale/fr.js | 2 +- .../extensions/ext-opensave/locale/zh-CN.js | 2 +- .../ext-overview_window/dragmove/dragmove.js | 90 +- .../ext-overview_window.js | 179 +- .../extensions/ext-panning/ext-panning.js | 70 +- .../extensions/ext-panning/locale/en.js | 2 +- .../extensions/ext-panning/locale/zh-CN.js | 2 +- .../extensions/ext-polystar/ext-polystar.js | 508 +- .../extensions/ext-polystar/locale/en.js | 2 +- .../extensions/ext-polystar/locale/fr.js | 2 +- .../extensions/ext-polystar/locale/zh-CN.js | 2 +- .../extensions/ext-shapes/ext-shapes.js | 153 +- src/editor/extensions/ext-shapes/locale/en.js | 2 +- src/editor/extensions/ext-shapes/locale/fr.js | 2 +- .../extensions/ext-shapes/locale/zh-CN.js | 2 +- .../extensions/ext-storage/ext-storage.js | 130 +- .../extensions/ext-storage/locale/de.js | 2 +- .../extensions/ext-storage/locale/en.js | 2 +- .../extensions/ext-storage/locale/fr.js | 2 +- .../extensions/ext-storage/locale/zh-CN.js | 2 +- .../extensions/ext-storage/storageDialog.js | 176 +- src/editor/index.html | 26 +- src/editor/locale.js | 25 +- src/editor/locale/lang.af.js | 4 +- src/editor/locale/lang.ar.js | 4 +- src/editor/locale/lang.az.js | 4 +- src/editor/locale/lang.be.js | 4 +- src/editor/locale/lang.bg.js | 4 +- src/editor/locale/lang.ca.js | 4 +- src/editor/locale/lang.cs.js | 4 +- src/editor/locale/lang.cy.js | 4 +- src/editor/locale/lang.da.js | 4 +- src/editor/locale/lang.de.js | 4 +- src/editor/locale/lang.el.js | 4 +- src/editor/locale/lang.en.js | 2 +- src/editor/locale/lang.es.js | 4 +- src/editor/locale/lang.et.js | 2 +- src/editor/locale/lang.fa.js | 2 +- src/editor/locale/lang.fi.js | 2 +- src/editor/locale/lang.fr.js | 2 +- src/editor/locale/lang.fy.js | 2 +- src/editor/locale/lang.ga.js | 2 +- src/editor/locale/lang.gl.js | 2 +- src/editor/locale/lang.he.js | 2 +- src/editor/locale/lang.hi.js | 2 +- src/editor/locale/lang.hr.js | 2 +- src/editor/locale/lang.hu.js | 2 +- src/editor/locale/lang.hy.js | 2 +- src/editor/locale/lang.id.js | 2 +- src/editor/locale/lang.is.js | 2 +- src/editor/locale/lang.it.js | 2 +- src/editor/locale/lang.ja.js | 2 +- src/editor/locale/lang.ko.js | 2 +- src/editor/locale/lang.lt.js | 2 +- src/editor/locale/lang.lv.js | 2 +- src/editor/locale/lang.mk.js | 2 +- src/editor/locale/lang.ms.js | 2 +- src/editor/locale/lang.mt.js | 2 +- src/editor/locale/lang.nl.js | 2 +- src/editor/locale/lang.no.js | 2 +- src/editor/locale/lang.pl.js | 2 +- src/editor/locale/lang.pt-BR.js | 2 +- src/editor/locale/lang.pt-PT.js | 2 +- src/editor/locale/lang.ro.js | 2 +- src/editor/locale/lang.ru.js | 2 +- src/editor/locale/lang.sk.js | 2 +- src/editor/locale/lang.sl.js | 2 +- src/editor/locale/lang.sq.js | 2 +- src/editor/locale/lang.sr.js | 2 +- src/editor/locale/lang.sv.js | 2 +- src/editor/locale/lang.sw.js | 2 +- src/editor/locale/lang.test.js | 2 +- src/editor/locale/lang.th.js | 2 +- src/editor/locale/lang.tl.js | 2 +- src/editor/locale/lang.tr.js | 2 +- src/editor/locale/lang.uk.js | 2 +- src/editor/locale/lang.vi.js | 2 +- src/editor/locale/lang.yi.js | 2 +- src/editor/locale/lang.zh-CN.js | 2 +- src/editor/locale/lang.zh-HK.js | 2 +- src/editor/locale/lang.zh-TW.js | 2 +- src/editor/panels/BottomPanel.js | 182 +- src/editor/panels/LayersPanel.js | 374 +- src/editor/panels/LeftPanel.js | 165 +- src/editor/panels/TopPanel.js | 954 ++-- src/editor/touch.js | 35 +- src/svgcanvas/blur-event.js | 116 +- src/svgcanvas/clear.js | 45 +- src/svgcanvas/coords.js | 442 +- src/svgcanvas/copy-elem.js | 46 +- src/svgcanvas/dataStorage.js | 18 +- src/svgcanvas/draw.js | 608 +-- src/svgcanvas/elem-get-set.js | 706 +-- src/svgcanvas/event.js | 1981 ++++---- src/svgcanvas/history.js | 288 +- src/svgcanvas/historyrecording.js | 66 +- src/svgcanvas/jQuery.attr.js | 44 +- src/svgcanvas/json.js | 58 +- src/svgcanvas/layer.js | 107 +- src/svgcanvas/math.js | 114 +- src/svgcanvas/namespaces.js | 14 +- src/svgcanvas/paste-elem.js | 96 +- src/svgcanvas/path-actions.js | 1102 ++--- src/svgcanvas/path-method.js | 762 +-- src/svgcanvas/path.js | 625 +-- src/svgcanvas/recalculate.js | 728 +-- src/svgcanvas/sanitize.js | 246 +- src/svgcanvas/select.js | 358 +- src/svgcanvas/selected-elem.js | 869 ++-- src/svgcanvas/selection.js | 292 +- src/svgcanvas/svg-exec.js | 934 ++-- src/svgcanvas/svgcanvas.js | 1078 ++-- src/svgcanvas/svgroot.js | 8 +- src/svgcanvas/text-actions.js | 343 +- src/svgcanvas/undo.js | 194 +- src/svgcanvas/utilities.js | 883 ++-- web-dev-server.config.mjs | 34 +- 251 files changed, 19760 insertions(+), 19935 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.js diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 40a0b115..00000000 --- a/.eslintignore +++ /dev/null @@ -1,30 +0,0 @@ -node_modules -ignore - -coverage -instrumented -dist -docs/jsdoc -archive - -jsconfig.json -releases -!.eslintrc.js -!.ncurc.js - -es-dev-server.config.js -nyc.config.js - -svgedit-custom.css - -# Vendor/minified files -src/editor/jquery.min.js - -# Previously minified though exporting -src/editor/js-hotkeys - -src/editor/extensions/ext-mathjax/mathjax - -# jquery files -src/editor/jgraduate/jQuery.jPicker.js - diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index e6096b1b..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,96 +0,0 @@ -"use strict"; - -module.exports = { - extends: [ - "plugin:compat/recommended", - "plugin:node/recommended", - "plugin:no-unsanitized/DOM", - "plugin:promise/recommended", - "plugin:import/errors", - "plugin:markdown/recommended", - "eslint:recommended" - ], - plugins: [ "jsdoc", "promise", "html", "import" ], - parserOptions: { - ecmaVersion: 2020, - sourceType: "module" - }, - env: { - browser: true, - es6: true - }, - rules: { - /** @todo len should probably more 120-150 */ - "max-len": [ "warn", { "code": 250 } ], - "indent": [ "error", 2 ], - "no-var": "error", - /** @todo this rule should be actived. needs some courage as this rule is broken in many places... */ - "one-var": [ "error", "never" ], - /** @todo jsdoc should be made warn or error */ - "valid-jsdoc": "off", - /** @todo no param reassign creates too many warnings but should be a warning */ - "no-param-reassign": "off", - /** @todo no use before define creates too many warnings but should be a warning */ - "no-use-before-define": "off", - /** @todo camel case creates too many warnings but should be a warning */ - "camelcase": "off", - "comma-dangle": [ "error" ], - "node/no-unsupported-features/es-syntax": 0, - "no-unused-vars": [ "error", { "argsIgnorePattern": "^_" } ], - "semi" : "error", - "prefer-const": "error", - "no-trailing-spaces": "error", - "array-bracket-spacing": [ "error", "always" ], - "comma-spacing": "error", - "object-curly-spacing": [ "error", "always" ], - "no-console": [ - "warn", - { "allow": [ "warn", "error", "info", "table" ] } - ], - "arrow-parens": [ "error", "always" ] - }, - overrides: [ - { - files: [ 'cypress/**/*' ], - extends: [ - "plugin:cypress/recommended" - ], - env: { - mocha: true, - node: true - }, - globals: { "assert": true }, - rules: { - // with ci, instrumented is not created before linter - "import/no-unresolved": [ 2, { ignore: [ 'instrumented' ] } ], - "node/no-missing-import": 0, - "node/no-unpublished-import": 0, - "node/no-unpublished-require": 0 - } - }, - { - files: [ 'docs/**/*' ], - rules: { // md files have example that don't need a strict checking - "no-undef": 0, - "import/no-unresolved": 0, - "node/no-missing-import": 0, - "jsdoc/check-examples": [ - "warn", - { - rejectExampleCodeRegex: "^`", - checkDefaults: true, - checkParams: true, - checkProperties: true - } - ] - } - }, - { - files: [ 'src/editor/locale/*.js' ], - rules: { // lang files may have long length - "max-len": "off", - "camelcase": "off" - } - } - ] -}; diff --git a/.gitignore b/.gitignore index c4f8ddb0..9c68b054 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ coverage instrumented .nyc_output .vscode -.eslintcache .DS_Store .idea dist diff --git a/.npmignore b/.npmignore index dbd7ab3e..b3fd8eec 100644 --- a/.npmignore +++ b/.npmignore @@ -2,5 +2,4 @@ lgtm.yml coverage/** .nyc_output instrumented/** -.eslintcache node_modules/** diff --git a/cypress/integration/ui/clipboard.js b/cypress/integration/ui/clipboard.js index 26d423b6..ae6b062e 100644 --- a/cypress/integration/ui/clipboard.js +++ b/cypress/integration/ui/clipboard.js @@ -1,14 +1,14 @@ import { visitAndApproveStorage -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' describe('UI - Clipboard', function () { beforeEach(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('Editor - Copy and paste', () => { - cy.get('#tool_source').click(); + cy.get('#tool_source').click() cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) @@ -17,47 +17,47 @@ describe('UI - Clipboard', function () { Layer 1 - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click(); - cy.get('#testCircle').should('exist'); - cy.get('#svg_1').should('not.exist'); - cy.get('#svg_2').should('not.exist'); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click() + cy.get('#testCircle').should('exist') + cy.get('#svg_1').should('not.exist') + cy.get('#svg_2').should('not.exist') // Copy. - cy.get('#testCircle').click().rightclick(); - cy.get('#cmenu_canvas a[href="#copy"]').click({ force: true }); + cy.get('#testCircle').click().rightclick() + cy.get('#cmenu_canvas a[href="#copy"]').click({ force: true }) // Paste. // Scrollbars fail to recenter in Cypress test. Works fine in reality. // Thus forcing click is needed since workspace is mostly offscreen. - cy.get('#svgroot').rightclick({ force: true }); - cy.get('#cmenu_canvas a[href="#paste"]').click({ force: true }); - cy.get('#testCircle').should('exist'); - cy.get('#svg_1').should('exist'); - cy.get('#svg_2').should('not.exist'); + cy.get('#svgroot').rightclick({ force: true }) + cy.get('#cmenu_canvas a[href="#paste"]').click({ force: true }) + cy.get('#testCircle').should('exist') + cy.get('#svg_1').should('exist') + cy.get('#svg_2').should('not.exist') // Cut. - cy.get('#testCircle').click().rightclick(); - cy.get('#cmenu_canvas a[href="#cut"]').click({ force: true }); - cy.get('#testCircle').should('not.exist'); - cy.get('#svg_1').should('exist'); - cy.get('#svg_2').should('not.exist'); + cy.get('#testCircle').click().rightclick() + cy.get('#cmenu_canvas a[href="#cut"]').click({ force: true }) + cy.get('#testCircle').should('not.exist') + cy.get('#svg_1').should('exist') + cy.get('#svg_2').should('not.exist') // Paste. // Scrollbars fail to recenter in Cypress test. Works fine in reality. // Thus forcing click is needed since workspace is mostly offscreen. - cy.get('#svgroot').rightclick({ force: true }); - cy.get('#cmenu_canvas a[href="#paste"]').click({ force: true }); - cy.get('#testCircle').should('not.exist'); - cy.get('#svg_1').should('exist'); - cy.get('#svg_2').should('exist'); + cy.get('#svgroot').rightclick({ force: true }) + cy.get('#cmenu_canvas a[href="#paste"]').click({ force: true }) + cy.get('#testCircle').should('not.exist') + cy.get('#svg_1').should('exist') + cy.get('#svg_2').should('exist') // Delete. - cy.get('#svg_2').click().rightclick(); - cy.get('#cmenu_canvas a[href="#delete"]').click({ force: true }); - cy.get('#svg_1').click().rightclick(); - cy.get('#cmenu_canvas a[href="#delete"]').click({ force: true }); - cy.get('#svg_1').should('not.exist'); - cy.get('#svg_2').should('not.exist'); - }); -}); + cy.get('#svg_2').click().rightclick() + cy.get('#cmenu_canvas a[href="#delete"]').click({ force: true }) + cy.get('#svg_1').click().rightclick() + cy.get('#cmenu_canvas a[href="#delete"]').click({ force: true }) + cy.get('#svg_1').should('not.exist') + cy.get('#svg_2').should('not.exist') + }) +}) diff --git a/cypress/integration/ui/control-points.js b/cypress/integration/ui/control-points.js index 0dcc6c3c..be8efd7c 100644 --- a/cypress/integration/ui/control-points.js +++ b/cypress/integration/ui/control-points.js @@ -1,15 +1,15 @@ import { visitAndApproveStorage -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' describe('UI - Control Points', function () { beforeEach(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('Editor - No parameters: Drag control point of arc path', () => { - const randomOffset = () => 2 + Math.round(10 + Math.random() * 40); - cy.get('#tool_source').click(); + const randomOffset = () => 2 + Math.round(10 + Math.random() * 40) + cy.get('#tool_source').click() cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` @@ -17,18 +17,18 @@ describe('UI - Control Points', function () { Layer 1 - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click({ force: true }); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click({ force: true }) - cy.get('#svg_1').click({ force: true }).click({ force: true }); + cy.get('#svg_1').click({ force: true }).click({ force: true }) cy.get('#pathpointgrip_0').trigger('mousedown', { which: 1, force: true }) .trigger('mousemove', randomOffset(), randomOffset(), { force: true }) - .trigger('mouseup', { force: true }); + .trigger('mouseup', { force: true }) cy.get('#pathpointgrip_1').trigger('mousedown', { which: 1, force: true }) .trigger('mousemove', randomOffset(), randomOffset(), { force: true }) - .trigger('mouseup', { force: true }); + .trigger('mouseup', { force: true }) - cy.get('#svg_1[d]').should('not.contain', 'NaN'); - }); -}); + cy.get('#svg_1[d]').should('not.contain', 'NaN') + }) +}) diff --git a/cypress/integration/ui/export.js b/cypress/integration/ui/export.js index f77877c8..128a5f83 100644 --- a/cypress/integration/ui/export.js +++ b/cypress/integration/ui/export.js @@ -1,20 +1,20 @@ import { visitAndApproveStorage, openMainMenu -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' describe('UI - Export tests', function () { beforeEach(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('Editor - No parameters: Has export button', () => { - openMainMenu(); - cy.get('#tool_export'); - }); + openMainMenu() + cy.get('#tool_export') + }) it('Editor - No parameters: Export button clicking; dialog opens', () => { - openMainMenu(); - cy.get('#tool_export').click({ force: true }); - cy.get('#dialog_content select'); - }); -}); + openMainMenu() + cy.get('#tool_export').click({ force: true }) + cy.get('#dialog_content select') + }) +}) diff --git a/cypress/integration/ui/issues/issue-359.js b/cypress/integration/ui/issues/issue-359.js index d93fb5b9..df448c22 100644 --- a/cypress/integration/ui/issues/issue-359.js +++ b/cypress/integration/ui/issues/issue-359.js @@ -1,15 +1,15 @@ import { visitAndApproveStorage -} from '../../../support/ui-test-helper.js'; +} from '../../../support/ui-test-helper.js' // See https://github.com/SVG-Edit/svgedit/issues/359 describe('Fix issue 359', function () { beforeEach(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('can undo without throwing', function () { - cy.get('#tool_source').click(); + cy.get('#tool_source').click() cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` @@ -17,10 +17,10 @@ describe('Fix issue 359', function () { Layer 1 - `, { parseSpecialCharSequences: false, force: true }); - cy.get('#tool_source_save').click(); - cy.get('#tool_undo').click(); - cy.get('#tool_redo').click(); // test also redo to make the test more comprehensive + `, { parseSpecialCharSequences: false, force: true }) + cy.get('#tool_source_save').click() + cy.get('#tool_undo').click() + cy.get('#tool_redo').click() // test also redo to make the test more comprehensive // if the undo throws an error to the console, the test will fail - }); -}); + }) +}) diff --git a/cypress/integration/ui/issues/issue-407.js b/cypress/integration/ui/issues/issue-407.js index a7597aed..fe39c12f 100644 --- a/cypress/integration/ui/issues/issue-407.js +++ b/cypress/integration/ui/issues/issue-407.js @@ -1,15 +1,15 @@ import { visitAndApproveStorage -} from '../../../support/ui-test-helper.js'; +} from '../../../support/ui-test-helper.js' // See https://github.com/SVG-Edit/svgedit/issues/407 describe('Fix issue 407', function () { beforeEach(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('can enter edit on text child', function () { - cy.get('#tool_source').click(); + cy.get('#tool_source').click() cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` @@ -20,16 +20,16 @@ describe('Fix issue 407', function () { hello - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click(); - cy.get('#svg_1').click().dblclick(); - cy.get('#a_text').should('exist'); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click() + cy.get('#svg_1').click().dblclick() + cy.get('#a_text').should('exist') cy.get('#a_text') .trigger('mousedown', { which: 1, force: true }) .trigger('mouseup', { force: true }) - .dblclick({ force: true }); + .dblclick({ force: true }) // svgedit use the #text text field to capture the text - cy.get('#text').type('1234', { force: true }); - cy.get('#a_text').should('have.text', 'he1234llo'); - }); -}); + cy.get('#text').type('1234', { force: true }) + cy.get('#a_text').should('have.text', 'he1234llo') + }) +}) diff --git a/cypress/integration/ui/issues/issue-408.js b/cypress/integration/ui/issues/issue-408.js index fdf1bb32..36df34a7 100644 --- a/cypress/integration/ui/issues/issue-408.js +++ b/cypress/integration/ui/issues/issue-408.js @@ -1,15 +1,15 @@ import { visitAndApproveStorage -} from '../../../support/ui-test-helper.js'; +} from '../../../support/ui-test-helper.js' // See https://github.com/SVG-Edit/svgedit/issues/408 describe('Fix issue 408', function () { beforeEach(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('should not throw when showing/saving svg content', function () { - cy.get('#tool_source').click(); + cy.get('#tool_source').click() cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` @@ -20,10 +20,10 @@ describe('Fix issue 408', function () { - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click(); - cy.get('#svg_6').click().dblclick(); // change context - cy.get('#tool_source').click(); // reopen tool_source - cy.get('#tool_source_save').should('exist'); // The save button should be here if it does not throw - }); -}); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click() + cy.get('#svg_6').click().dblclick() // change context + cy.get('#tool_source').click() // reopen tool_source + cy.get('#tool_source_save').should('exist') // The save button should be here if it does not throw + }) +}) diff --git a/cypress/integration/ui/issues/issue-423.js b/cypress/integration/ui/issues/issue-423.js index 6ab956fc..1de97313 100644 --- a/cypress/integration/ui/issues/issue-423.js +++ b/cypress/integration/ui/issues/issue-423.js @@ -1,15 +1,15 @@ import { visitAndApproveStorage -} from '../../../support/ui-test-helper.js'; +} from '../../../support/ui-test-helper.js' // See https://github.com/SVG-Edit/svgedit/issues/423 describe('Fix issue 423', function () { beforeEach(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('should not throw when undoing the move', function () { - cy.get('#tool_source').click(); + cy.get('#tool_source').click() cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` @@ -22,12 +22,12 @@ describe('Fix issue 423', function () { - `, { parseSpecialCharSequences: false, force: true }); - cy.get('#tool_source_save').click({ force: true }); + `, { parseSpecialCharSequences: false, force: true }) + cy.get('#tool_source_save').click({ force: true }) cy.get('#TANK1') .trigger('mousedown', { force: true }) .trigger('mousemove', 50, 0, { force: true }) - .trigger('mouseup', { force: true }); - cy.get('#tool_undo').click({ force: true }); - }); -}); + .trigger('mouseup', { force: true }) + cy.get('#tool_undo').click({ force: true }) + }) +}) diff --git a/cypress/integration/ui/issues/issue-660.js b/cypress/integration/ui/issues/issue-660.js index 3eeefc21..0f4a3694 100644 --- a/cypress/integration/ui/issues/issue-660.js +++ b/cypress/integration/ui/issues/issue-660.js @@ -1,16 +1,16 @@ import { visitAndApproveStorage -} from '../../../support/ui-test-helper.js'; +} from '../../../support/ui-test-helper.js' // See https://github.com/SVG-Edit/svgedit/issues/660 describe('Fix issue 660', function () { beforeEach(() => { - visitAndApproveStorage(); - cy.viewport(512, 512); - }); + visitAndApproveStorage() + cy.viewport(512, 512) + }) /** @todo: reenable this test when we understand why it is passing locally but not on ci */ it.skip('can resize text', function () { - cy.get('#tool_source').click(); + cy.get('#tool_source').click() cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` @@ -18,18 +18,18 @@ describe('Fix issue 660', function () { Layer 1 hello - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click({ force: true }); - cy.get('#a_text').should('exist'); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click({ force: true }) + cy.get('#a_text').should('exist') cy.get('#a_text') .trigger('mousedown', { which: 1, force: true }) - .trigger('mouseup', { force: true }); + .trigger('mouseup', { force: true }) cy.get('#selectorGrip_resize_s') .trigger('mousedown', { which: 1, force: true }) .trigger('mousemove', { clientX: 0, clientY: 600 }) - .trigger('mouseup', { force: true }); + .trigger('mouseup', { force: true }) // svgedit use the #text text field to capture the text cy.get('#a_text').should('have.attr', 'transform') - .and('equal', 'matrix(1 0 0 4.54639 0 -540.825)'); // Chrome 96 is matrix(1 0 0 4.17431 0 -325.367) - }); -}); + .and('equal', 'matrix(1 0 0 4.54639 0 -540.825)') // Chrome 96 is matrix(1 0 0 4.17431 0 -325.367) + }) +}) diff --git a/cypress/integration/ui/key-commands.js b/cypress/integration/ui/key-commands.js index 9c00fcc3..9ae6ff7c 100644 --- a/cypress/integration/ui/key-commands.js +++ b/cypress/integration/ui/key-commands.js @@ -1,14 +1,14 @@ import { visitAndApproveStorage -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' // See https://github.com/SVG-Edit/svgedit/issues/364 describe('Key commands', function () { beforeEach(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it.skip('cmd-A on empty canvas should not cause an error', function () { - cy.get('body').type('{cmd}a'); - }); -}); + cy.get('body').type('{cmd}a') + }) +}) diff --git a/cypress/integration/ui/scenario.js b/cypress/integration/ui/scenario.js index 4a0c23f7..a768e44b 100644 --- a/cypress/integration/ui/scenario.js +++ b/cypress/integration/ui/scenario.js @@ -1,190 +1,188 @@ import { visitAndApproveStorage -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + cy.get('#svgcontent').cleanSnapshot() +} describe('use various parts of svg-edit', function () { before(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('check tool_source', function () { - cy.get('#tool_source').click({ force: true }); + cy.get('#tool_source').click({ force: true }) cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` Layer 1 - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click({ force: true }); - testSnapshot(); - }); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click({ force: true }) + testSnapshot() + }) it('check tool_fhpath', function () { cy.get('#tool_fhpath') - .click({ force: true }); + .click({ force: true }) cy.get('#svgcontent') .trigger('mousemove', 200, 200, { force: true }) .trigger('mousedown', 200, 200, { force: true }) .trigger('mousemove', 20, 20, { force: true }) - .trigger('mouseup', { force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + testSnapshot() + }) it('check tool_text', function () { cy.get('#tool_text') - .click({ force: true }); + .click({ force: true }) cy.get('#svgcontent') - .trigger('mousedown', 46, 35, { force: true }) - .trigger('mouseup', { force: true }); + .trigger('mousedown', 46, 35, { force: true }) + .trigger('mouseup', { force: true }) // svgedit use the #text text field to capture the text - cy.get('#text').type('AB', { force: true }); - testSnapshot(); - }); + cy.get('#text').type('AB', { force: true }) + testSnapshot() + }) it('check tool_clone', function () { - cy.get('#svg_1').click({ force: true }); + cy.get('#svg_1').click({ force: true }) cy.get('#tool_clone') - .click({ force: true }); - testSnapshot(); - }); + .click({ force: true }) + testSnapshot() + }) it('check tool_italic', function () { - cy.get('#svg_1').click({ force: true }); + cy.get('#svg_1').click({ force: true }) cy.get('#tool_italic') - .click({ force: true }); - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(500); - testSnapshot(); - }); + .click({ force: true }) + testSnapshot() + }) it('check tool_bold', function () { - cy.get('#svg_1').click({ force: true }); + cy.get('#svg_1').click({ force: true }) cy.get('#tool_bold') - .click({ force: true }); - testSnapshot(); - }); + .click({ force: true }) + testSnapshot() + }) it('check tool_text_change_x_y_coordinate', function () { - cy.get('#svg_2').click({ force: true }); - for(let n = 0; n < 25; n ++){ + cy.get('#svg_2').click({ force: true }) + for (let n = 0; n < 25; n++) { cy.get('#selected_x').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - for(let n = 0; n < 25; n ++){ + for (let n = 0; n < 25; n++) { cy.get('#selected_y').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_text_change_font_size', function () { - cy.get('#svg_1').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_1').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#font_size').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_text_change_stroke_width', function () { - cy.get('#svg_1').click({ force: true }); + cy.get('#svg_1').click({ force: true }) cy.get('#stroke_width').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); - testSnapshot(); - }); + .click({ force: true }) + testSnapshot() + }) it('check tool_text_change_stoke_fill_color', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#stroke_color').shadow().find('#picker').eq(0).click({ force: true }); + cy.get('#svg_1').click({ force: true }) + cy.get('#stroke_color').shadow().find('#picker').eq(0).click({ force: true }) cy.get('#stroke_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('.QuickColor').eq(51).click({ force: true }); + .find('.QuickColor').eq(51).click({ force: true }) cy.get('#stroke_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('#Ok').eq(0).click({ force: true }); - cy.get('#fill_color').shadow().find('#picker').eq(0).click({ force: true }); + .find('#Ok').eq(0).click({ force: true }) + cy.get('#fill_color').shadow().find('#picker').eq(0).click({ force: true }) cy.get('#fill_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('.QuickColor').eq(3).click({ force: true }); + .find('.QuickColor').eq(3).click({ force: true }) cy.get('#fill_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('#Ok').eq(0).click({ force: true }); - testSnapshot(); - }); + .find('#Ok').eq(0).click({ force: true }) + testSnapshot() + }) it('check tool_text_anchor_start', function () { - cy.get('#svg_1').click({ force: true }); + cy.get('#svg_1').click({ force: true }) cy.get('#tool_text_anchor_start') - .click({ force: true }); - testSnapshot(); - }); + .click({ force: true }) + testSnapshot() + }) it('check tool_text_anchor_middle', function () { - cy.get('#svg_1').click({ force: true }); + cy.get('#svg_1').click({ force: true }) cy.get('#tool_text_anchor_middle') - .click({ force: true }); - testSnapshot(); - }); + .click({ force: true }) + testSnapshot() + }) it('check tool_text_anchor_end', function () { - cy.get('#svg_1').click({ force: true }); + cy.get('#svg_1').click({ force: true }) cy.get('#tool_text_anchor_end') - .click({ force: true }); - testSnapshot(); - }); + .click({ force: true }) + testSnapshot() + }) it('check tool_text_change_rotation', function () { - cy.get('#svg_2').click({ force: true }); - for(let n = 0; n < 5; n ++){ + cy.get('#svg_2').click({ force: true }) + for (let n = 0; n < 5; n++) { cy.get('#angle').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_text_change_blur', function () { - cy.get('#svg_2').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_2').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#blur').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_text_change_opacity', function () { - cy.get('#svg_2').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_2').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#opacity').shadow().find('elix-number-spin-box').eq(0).shadow().find('#downButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_text_align_to_page', function () { - cy.get('#svg_2').click({ force: true }); - cy.get('#tool_position').shadow().find('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened'); + cy.get('#svg_2').click({ force: true }) + cy.get('#tool_position').shadow().find('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened') cy.get('#tool_position').find('se-list-item').eq(2).shadow().find('elix-option').eq(0) - .click({ force: true }); - testSnapshot(); - }); + .click({ force: true }) + testSnapshot() + }) it('check tool_text_change_class', function () { - cy.get('#svg_2').click({ force: true }); + cy.get('#svg_2').click({ force: true }) cy.get('#elem_class').shadow().find('elix-input').eq(0).shadow().find('#inner').eq(0) - .type('svg_2_class{enter}', { force: true }); + .type('svg_2_class{enter}', { force: true }) cy.get('#svg_2') .should('satisfy', ($el) => { - const classList = Array.from($el[0].classList); - return classList.includes('svg_2_class'); - }); - }); + const classList = Array.from($el[0].classList) + return classList.includes('svg_2_class') + }) + }) it('check tool_text_change_id', function () { - cy.get('#svg_2').click({ force: true }).click({ force: true }); + cy.get('#svg_2').click({ force: true }).click({ force: true }) cy.get('#elem_id').shadow().find('elix-input').eq(0).shadow().find('#inner').eq(0) - .type('_id{enter}', { force: true }); + .type('_id{enter}', { force: true }) cy.get('#svg_2_id') .should('satisfy', ($el) => { - const classList = Array.from($el[0].classList); - return classList.includes('svg_2_class'); - }); - }); + const classList = Array.from($el[0].classList) + return classList.includes('svg_2_class') + }) + }) it('check tool_text_delete', function () { - cy.get('#svg_2_id').click({ force: true }); - cy.get('#tool_delete').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_2_id').click({ force: true }) + cy.get('#tool_delete').click({ force: true }) + testSnapshot() + }) it('check tool_text_change_font_family', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#tool_font_family').shadow().find('select').select("Serif"); - testSnapshot(); - }); -}); + cy.get('#svg_1').click({ force: true }) + cy.get('#tool_font_family').shadow().find('select').select('Serif') + testSnapshot() + }) +}) diff --git a/cypress/integration/ui/scenario1.js b/cypress/integration/ui/scenario1.js index 55aaa2a3..5dff79ba 100644 --- a/cypress/integration/ui/scenario1.js +++ b/cypress/integration/ui/scenario1.js @@ -1,55 +1,55 @@ import { visitAndApproveStorage -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + cy.get('#svgcontent').cleanSnapshot() +} describe('use all parts of svg-edit', function () { before(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('check tool_source_set', function () { - cy.get('#tool_source').click({ force: true }); + cy.get('#tool_source').click({ force: true }) cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` Layer 1 - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click({ force: true }); - testSnapshot(); - }); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click({ force: true }) + testSnapshot() + }) it('check tool_shape', function () { - cy.get('#tool_shapelib').shadow().find('.overall').eq(0).click({ force: true }); - cy.get('[data-shape="heart"]').click({ force: true }); + cy.get('#tool_shapelib').shadow().find('.overall').eq(0).click({ force: true }) + cy.get('[data-shape="heart"]').click({ force: true }) cy.get('#svgcontent') .trigger('mousemove', 200, 200, { force: true }) .trigger('mousedown', 200, 200, { force: true }) .trigger('mousemove', 20, 20, { force: true }) - .trigger('mouseup', { force: true }); + .trigger('mouseup', { force: true }) cy.get('#selectorGrip_rotate') .trigger('mousedown') .trigger('mousemove', 20, 20, { force: true }) - .trigger('mouseup', { force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + testSnapshot() + }) it('check tool_image', function () { - cy.get('#tool_image').click({ force: true }); + cy.get('#tool_image').click({ force: true }) cy.get('#svgcontent') .trigger('mousedown', 100, 100, { force: true }) .trigger('mousemove', 120, 120, { force: true }) - .trigger('mouseup', { force: true }); + .trigger('mouseup', { force: true }) // eslint-disable-next-line promise/catch-or-return cy.window() // eslint-disable-next-line promise/always-return .then(($win) => { - cy.stub($win, 'prompt').returns('./images/logo.svg'); - cy.contains('OK'); - }); - testSnapshot(); - }); -}); + cy.stub($win, 'prompt').returns('./images/logo.svg') + cy.contains('OK') + }) + testSnapshot() + }) +}) diff --git a/cypress/integration/ui/scenario2.js b/cypress/integration/ui/scenario2.js index 5390b972..c0051639 100644 --- a/cypress/integration/ui/scenario2.js +++ b/cypress/integration/ui/scenario2.js @@ -1,124 +1,124 @@ import { visitAndApproveStorage -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + cy.get('#svgcontent').cleanSnapshot() +} describe('use all parts of svg-edit', function () { before(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('check tool_source_set', function () { - cy.get('#tool_source').click({ force: true }); + cy.get('#tool_source').click({ force: true }) cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` Layer 1 - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click({ force: true }); - testSnapshot(); - }); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click({ force: true }) + testSnapshot() + }) it('check tool_circle', function () { cy.get('#tool_circle') - .click({ force: true }); + .click({ force: true }) cy.get('#svgcontent') .trigger('mousedown', 150, 150, { force: true }) .trigger('mousemove', 250, 200, { force: true }) - .trigger('mouseup', { force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + testSnapshot() + }) it('check tool_fhellipse', function () { cy.get('#tool_fhellipse') - .click({ force: true }); + .click({ force: true }) cy.get('#svgcontent') .trigger('mousedown', 200, 80, { force: true }) .trigger('mousemove', 320, 80, { force: true }) .trigger('mousemove', 320, 180, { force: true }) .trigger('mousemove', 200, 180, { force: true }) .trigger('mousemove', 200, 80, { force: true }) - .trigger('mouseup', 200, 80, { force: true }); - testSnapshot(); - }); + .trigger('mouseup', 200, 80, { force: true }) + testSnapshot() + }) it('check tool_ellipse', function () { - cy.get('#tool_ellipse').click({ force: true }); + cy.get('#tool_ellipse').click({ force: true }) cy.get('#svgcontent') .trigger('mousedown', 75, 150, { force: true }) .trigger('mousemove', 130, 175, { force: true }) - .trigger('mouseup', { force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + testSnapshot() + }) it('check tool_circle_change_fill_color', function () { - cy.get('#svg_2').click({ force: true }); + cy.get('#svg_2').click({ force: true }) cy.get('#js-se-palette').find('.square').eq(8) - .click({ force: true }); - testSnapshot(); - }); + .click({ force: true }) + testSnapshot() + }) it('check tool_circle_change_opacity', function () { - cy.get('#svg_2').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_2').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#opacity').shadow().find('elix-number-spin-box').eq(0).shadow().find('#downButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_ellipse_change_rotation', function () { - cy.get('#svg_3').click({ force: true }); - for(let n = 0; n < 5; n ++){ + cy.get('#svg_3').click({ force: true }) + for (let n = 0; n < 5; n++) { cy.get('#angle').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_ellipse_change_blur', function () { - cy.get('#svg_3').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_3').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#blur').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_ellipse_change_cx_cy_coordinate', function () { - cy.get('#svg_3').click({ force: true }); - for(let n = 0; n < 25; n ++){ + cy.get('#svg_3').click({ force: true }) + for (let n = 0; n < 25; n++) { cy.get('#ellipse_cx').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - for(let n = 0; n < 25; n ++){ + for (let n = 0; n < 25; n++) { cy.get('#ellipse_cy').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_ellipse_change_rx_ry_radius', function () { - cy.get('#svg_3').click({ force: true }); - for(let n = 0; n < 25; n ++){ + cy.get('#svg_3').click({ force: true }) + for (let n = 0; n < 25; n++) { cy.get('#ellipse_rx').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - for(let n = 0; n < 25; n ++){ + for (let n = 0; n < 25; n++) { cy.get('#ellipse_ry').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_ellipse_bring_to_back', function () { - cy.get('#svg_2').click({ force: true }); - cy.get('#tool_move_bottom').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_2').click({ force: true }) + cy.get('#tool_move_bottom').click({ force: true }) + testSnapshot() + }) it('check tool_ellipse_bring_to_front', function () { - cy.get('#svg_2').click({ force: true }); - cy.get('#tool_move_top').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_2').click({ force: true }) + cy.get('#tool_move_top').click({ force: true }) + testSnapshot() + }) it('check tool_ellipse_clone', function () { - cy.get('#svg_2').click({ force: true }); - cy.get('#tool_clone').click({ force: true }); - testSnapshot(); - }); -}); + cy.get('#svg_2').click({ force: true }) + cy.get('#tool_clone').click({ force: true }) + testSnapshot() + }) +}) diff --git a/cypress/integration/ui/scenario3.js b/cypress/integration/ui/scenario3.js index 496d340c..0150466c 100644 --- a/cypress/integration/ui/scenario3.js +++ b/cypress/integration/ui/scenario3.js @@ -1,31 +1,31 @@ import { visitAndApproveStorage -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + cy.get('#svgcontent').cleanSnapshot() +} describe('use all parts of svg-edit', function () { before(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('check tool_source_set', function () { - cy.get('#tool_source').click({ force: true }); + cy.get('#tool_source').click({ force: true }) cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` Layer 1 - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click({ force: true }); - testSnapshot(); - }); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click({ force: true }) + testSnapshot() + }) it('check tool_path', function () { cy.get('#tool_path') - .click({ force: true }); + .click({ force: true }) cy.get('#svgcontent') .trigger('mousedown', 50, 50, { force: true }) .trigger('mouseup', { force: true }) @@ -37,49 +37,49 @@ describe('use all parts of svg-edit', function () { .trigger('mouseup', { force: true }) .trigger('mousemove', 0, 0, { force: true }) .trigger('mousedown', 0, 0, { force: true }) - .trigger('mouseup', { force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + testSnapshot() + }) it('check tool_path_change_node_xy', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#svg_1').dblclick({ force: true }); - for(let n = 0; n < 25; n ++){ + cy.get('#svg_1').click({ force: true }) + cy.get('#svg_1').dblclick({ force: true }) + for (let n = 0; n < 25; n++) { cy.get('#path_node_x').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - for(let n = 0; n < 25; n ++){ + for (let n = 0; n < 25; n++) { cy.get('#path_node_y').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_path_change_seg_type', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#svg_1').dblclick({ force: true }); - cy.get('#seg_type').shadow().find('select').select('6').should('have.value', '6'); + cy.get('#svg_1').click({ force: true }) + cy.get('#svg_1').dblclick({ force: true }) + cy.get('#seg_type').shadow().find('select').select('6').should('have.value', '6') cy.get('#ctrlpointgrip_3c1') .trigger('mousedown', { force: true }) .trigger('mousemove', 130, 175, { force: true }) - .trigger('mouseup', { force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + testSnapshot() + }) it('check tool_path_change_clone_node', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#svg_1').dblclick({ force: true }); - cy.get('#tool_node_clone').click({ force: true }); + cy.get('#svg_1').click({ force: true }) + cy.get('#svg_1').dblclick({ force: true }) + cy.get('#tool_node_clone').click({ force: true }) cy.get('#pathpointgrip_4') .trigger('mousedown', { force: true }) .trigger('mousemove', 130, 175, { force: true }) - .trigger('mouseup', { force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + testSnapshot() + }) it('check tool_path_openclose', function () { - cy.get('#tool_select').click({ force: true }); - cy.get('#svg_1').click({ force: true }); - cy.get('#svg_1').dblclick({ force: true }); - cy.get('#tool_openclose_path').click({ force: true }); - testSnapshot(); - }); + cy.get('#tool_select').click({ force: true }) + cy.get('#svg_1').click({ force: true }) + cy.get('#svg_1').dblclick({ force: true }) + cy.get('#tool_openclose_path').click({ force: true }) + testSnapshot() + }) /* it('check tool_path_add_subpath', function () { cy.get('#tool_add_subpath').click({ force: true }); cy.get('#svgcontent') @@ -97,4 +97,4 @@ describe('use all parts of svg-edit', function () { cy.get('#tool_select').click({ force: true }); testSnapshot(); }); */ -}); +}) diff --git a/cypress/integration/ui/scenario4.js b/cypress/integration/ui/scenario4.js index 51e0bea5..db3b91d8 100644 --- a/cypress/integration/ui/scenario4.js +++ b/cypress/integration/ui/scenario4.js @@ -1,164 +1,164 @@ import { visitAndApproveStorage -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + cy.get('#svgcontent').cleanSnapshot() +} describe('use all parts of svg-edit', function () { before(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('check tool_source_set', function () { - cy.get('#tool_source').click({ force: true }); + cy.get('#tool_source').click({ force: true }) cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` Layer 1 - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click({ force: true }); - testSnapshot(); - }); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click({ force: true }) + testSnapshot() + }) it('check tool_rect', function () { cy.get('#tool_rect') - .click({ force: true }); + .click({ force: true }) cy.get('#svgcontent') .trigger('mousedown', 150, 150, { force: true }) .trigger('mousemove', 250, 200, { force: true }) - .trigger('mouseup', { force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + testSnapshot() + }) it('check tool_fhrect', function () { cy.get('#tool_fhrect') - .click({ force: true }); + .click({ force: true }) cy.get('#svgcontent') .trigger('mousedown', 200, 80, { force: true }) .trigger('mousemove', 320, 80, { force: true }) .trigger('mousemove', 320, 180, { force: true }) .trigger('mousemove', 200, 180, { force: true }) .trigger('mousemove', 200, 80, { force: true }) - .trigger('mouseup', 200, 80, { force: true }); - testSnapshot(); - }); + .trigger('mouseup', 200, 80, { force: true }) + testSnapshot() + }) it('check tool_square', function () { - cy.get('#tool_square').click({ force: true }); + cy.get('#tool_square').click({ force: true }) cy.get('#svgcontent') .trigger('mousedown', 75, 150, { force: true }) .trigger('mousemove', 125, 200, { force: true }) - .trigger('mouseup', { force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + testSnapshot() + }) it('check tool_rect_change_fill_color', function () { - cy.get('#svg_1').click({ force: true }); + cy.get('#svg_1').click({ force: true }) cy.get('#js-se-palette').find('.square').eq(8) - .click({ force: true }); - testSnapshot(); - }); + .click({ force: true }) + testSnapshot() + }) it('check tool_rect_change_rotation', function () { - cy.get('#svg_1').click({ force: true }); - for(let n = 0; n < 5; n ++){ + cy.get('#svg_1').click({ force: true }) + for (let n = 0; n < 5; n++) { cy.get('#angle').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_rect_change_blur', function () { - cy.get('#svg_1').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_1').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#blur').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_rect_change_opacity', function () { - cy.get('#svg_1').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_1').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#opacity').shadow().find('elix-number-spin-box').eq(0).shadow().find('#downButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_fhrect_change_x_y_coordinate', function () { - cy.get('#svg_2').click({ force: true }); - for(let n = 0; n < 25; n ++){ + cy.get('#svg_2').click({ force: true }) + for (let n = 0; n < 25; n++) { cy.get('#selected_x').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - for(let n = 0; n < 25; n ++){ + for (let n = 0; n < 25; n++) { cy.get('#selected_y').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_fhrect_change_width_height', function () { - cy.get('#svg_2').click({ force: true }); - for(let n = 0; n < 25; n ++){ + cy.get('#svg_2').click({ force: true }) + for (let n = 0; n < 25; n++) { cy.get('#rect_width').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - for(let n = 0; n < 25; n ++){ + for (let n = 0; n < 25; n++) { cy.get('#rect_height').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_square_clone', function () { - cy.get('#svg_3').click({ force: true }); - cy.get('#tool_clone').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_3').click({ force: true }) + cy.get('#tool_clone').click({ force: true }) + testSnapshot() + }) it('check tool_square_bring_to_back', function () { - cy.get('#svg_3').click({ force: true }); - cy.get('#tool_move_bottom').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_3').click({ force: true }) + cy.get('#tool_move_bottom').click({ force: true }) + testSnapshot() + }) it('check tool_square_bring_to_front', function () { - cy.get('#svg_3').click({ force: true }); - cy.get('#tool_move_top').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_3').click({ force: true }) + cy.get('#tool_move_top').click({ force: true }) + testSnapshot() + }) it('check tool_square_change_corner_radius', function () { - cy.get('#svg_4').click({ force: true }); - for(let n = 0; n < 25; n ++){ + cy.get('#svg_4').click({ force: true }) + for (let n = 0; n < 25; n++) { cy.get('#rect_rx').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_rect_change_to_path', function () { - cy.get('#svg_2').click({ force: true }); - cy.get('#tool_topath').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_2').click({ force: true }) + cy.get('#tool_topath').click({ force: true }) + testSnapshot() + }) it('check tool_rect_delete', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#tool_delete').click({ force: true }); - cy.get('#svg_3').click({ force: true }); - cy.get('#tool_delete').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_1').click({ force: true }) + cy.get('#tool_delete').click({ force: true }) + cy.get('#svg_3').click({ force: true }) + cy.get('#tool_delete').click({ force: true }) + testSnapshot() + }) it('check tool_rect_change_class', function () { - cy.get('#svg_2').click({ force: true }); + cy.get('#svg_2').click({ force: true }) cy.get('#elem_class').shadow().find('elix-input').eq(0).shadow().find('#inner').eq(0) - .type('svg_2_class{enter}', { force: true }); + .type('svg_2_class{enter}', { force: true }) cy.get('#svg_2') .should('satisfy', ($el) => { - const classList = Array.from($el[0].classList); - return classList.includes('svg_2_class'); - }); - }); + const classList = Array.from($el[0].classList) + return classList.includes('svg_2_class') + }) + }) it('check tool_rect_change_id', function () { - cy.get('#svg_2').click({ force: true }).click({ force: true }); + cy.get('#svg_2').click({ force: true }).click({ force: true }) cy.get('#elem_id').shadow().find('elix-input').eq(0).shadow().find('#inner').eq(0) - .type('_id{enter}', { force: true }); + .type('_id{enter}', { force: true }) cy.get('#svg_2_id') .should('satisfy', ($el) => { - const classList = Array.from($el[0].classList); - return classList.includes('svg_2_class'); - }); - }); -}); + const classList = Array.from($el[0].classList) + return classList.includes('svg_2_class') + }) + }) +}) diff --git a/cypress/integration/ui/scenario5.js b/cypress/integration/ui/scenario5.js index e6b5fd7f..8bee0396 100644 --- a/cypress/integration/ui/scenario5.js +++ b/cypress/integration/ui/scenario5.js @@ -1,153 +1,153 @@ import { visitAndApproveStorage -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + cy.get('#svgcontent').cleanSnapshot() +} describe('use all parts of svg-edit', function () { before(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('check tool_source_set', function () { - cy.get('#tool_source').click({ force: true }); + cy.get('#tool_source').click({ force: true }) cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` Layer 1 - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click({ force: true }); - testSnapshot(); - }); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click({ force: true }) + testSnapshot() + }) it('check tool_line', function () { cy.get('#tool_line') - .click({ force: true }); + .click({ force: true }) cy.get('#svgcontent') .trigger('mousemove', 200, 200, { force: true }) .trigger('mousedown', 200, 200, { force: true }) .trigger('mousemove', 250, 250, { force: true }) - .trigger('mouseup', { force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + testSnapshot() + }) it('check tool_line_change_class', function () { - cy.get('#svg_1').click({ force: true }); + cy.get('#svg_1').click({ force: true }) cy.get('#elem_class').shadow().find('elix-input').eq(0).shadow().find('#inner').eq(0) - .type('svg_1_class{enter}', { force: true }); + .type('svg_1_class{enter}', { force: true }) cy.get('#svg_1') .should('satisfy', ($el) => { - const classList = Array.from($el[0].classList); - return classList.includes('svg_1_class'); - }); - }); + const classList = Array.from($el[0].classList) + return classList.includes('svg_1_class') + }) + }) it('check tool_line_change_id', function () { - cy.get('#svg_1').click({ force: true }).click({ force: true }); + cy.get('#svg_1').click({ force: true }).click({ force: true }) cy.get('#elem_id').shadow().find('elix-input').eq(0).shadow().find('#inner').eq(0) - .type('_id{enter}', { force: true }); + .type('_id{enter}', { force: true }) cy.get('#svg_1_id') .should('satisfy', ($el) => { - const classList = Array.from($el[0].classList); - return classList.includes('svg_1_class'); - }); - }); + const classList = Array.from($el[0].classList) + return classList.includes('svg_1_class') + }) + }) it('check tool_line_change_rotation', function () { - cy.get('#svg_1_id').click({ force: true }); - for(let n = 0; n < 5; n ++){ + cy.get('#svg_1_id').click({ force: true }) + for (let n = 0; n < 5; n++) { cy.get('#angle').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_line_change_blur', function () { - cy.get('#svg_1_id').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_1_id').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#blur').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_line_change_opacity', function () { - cy.get('#svg_1_id').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_1_id').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#opacity').shadow().find('elix-number-spin-box').eq(0).shadow().find('#downButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_line_delete', function () { - cy.get('#svg_1_id').click({ force: true }); - cy.get('#tool_delete').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_1_id').click({ force: true }) + cy.get('#tool_delete').click({ force: true }) + testSnapshot() + }) it('check tool_line_clone', function () { cy.get('#tool_line') - .click({ force: true }); + .click({ force: true }) cy.get('#svgcontent') .trigger('mousemove', 200, 200, { force: true }) .trigger('mousedown', 200, 200, { force: true }) .trigger('mousemove', 250, 250, { force: true }) - .trigger('mouseup', { force: true }); - cy.get('#svg_2').click({ force: true }); - cy.get('#tool_clone').click({ force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + cy.get('#svg_2').click({ force: true }) + cy.get('#tool_clone').click({ force: true }) + testSnapshot() + }) it('check tool_line_bring_to_back', function () { - cy.get('#svg_2').click({ force: true }); - cy.get('#tool_move_bottom').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_2').click({ force: true }) + cy.get('#tool_move_bottom').click({ force: true }) + testSnapshot() + }) it('check tool_line_bring_to_front', function () { - cy.get('#svg_2').click({ force: true }); - cy.get('#tool_move_top').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_2').click({ force: true }) + cy.get('#tool_move_top').click({ force: true }) + testSnapshot() + }) it('check tool_line_change_x_y_coordinate', function () { - cy.get('#svg_2').click({ force: true }); - for(let n = 0; n < 25; n ++){ + cy.get('#svg_2').click({ force: true }) + for (let n = 0; n < 25; n++) { cy.get('#line_x1').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - for(let n = 0; n < 25; n ++){ + for (let n = 0; n < 25; n++) { cy.get('#line_y1').shadow().find('elix-number-spin-box').eq(0).shadow().find('#downButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - for(let n = 0; n < 25; n ++){ + for (let n = 0; n < 25; n++) { cy.get('#line_x2').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - for(let n = 0; n < 25; n ++){ + for (let n = 0; n < 25; n++) { cy.get('#line_y2').shadow().find('elix-number-spin-box').eq(0).shadow().find('#downButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_line_change_stroke_width', function () { - cy.get('#svg_2').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_2').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#stroke_width').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_line_change_stoke_color', function () { - cy.get('#svg_3').click({ force: true }); - cy.get('#stroke_color').shadow().find('#picker').eq(0).click({ force: true }); + cy.get('#svg_3').click({ force: true }) + cy.get('#stroke_color').shadow().find('#picker').eq(0).click({ force: true }) cy.get('#stroke_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('.QuickColor').eq(9).click({ force: true }); + .find('.QuickColor').eq(9).click({ force: true }) cy.get('#stroke_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('#Ok').eq(0).click({ force: true }); - testSnapshot(); - }); + .find('#Ok').eq(0).click({ force: true }) + testSnapshot() + }) it('check tool_line_align_to_page', function () { - cy.get('#svg_3').click({ force: true }); - cy.get('#tool_position').shadow().find('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened'); + cy.get('#svg_3').click({ force: true }) + cy.get('#tool_position').shadow().find('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened') cy.get('#tool_position').find('se-list-item').eq(2).shadow().find('elix-option').eq(0) - .click({ force: true }); - testSnapshot(); - }); -}); + .click({ force: true }) + testSnapshot() + }) +}) diff --git a/cypress/integration/ui/scenario6.js b/cypress/integration/ui/scenario6.js index 992393de..240931b5 100644 --- a/cypress/integration/ui/scenario6.js +++ b/cypress/integration/ui/scenario6.js @@ -1,108 +1,108 @@ import { visitAndApproveStorage -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + cy.get('#svgcontent').cleanSnapshot() +} describe('use all parts of svg-edit', function () { before(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('check tool_source_set', function () { - cy.get('#tool_source').click({ force: true }); + cy.get('#tool_source').click({ force: true }) cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` Layer 1 - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click({ force: true }); - testSnapshot(); - }); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click({ force: true }) + testSnapshot() + }) it('check tool_polygon', function () { cy.get('#tool_polygon') - .click({ force: true }); + .click({ force: true }) cy.get('#svgcontent') .trigger('mousedown', 325, 250, { force: true }) .trigger('mousemove', 325, 345, { force: true }) - .trigger('mouseup', { force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + testSnapshot() + }) it('check tool_polygon_clone', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#tool_clone').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_1').click({ force: true }) + cy.get('#tool_clone').click({ force: true }) + testSnapshot() + }) it('check tool_polygon_change_class', function () { - cy.get('#svg_2').click({ force: true }); + cy.get('#svg_2').click({ force: true }) cy.get('#elem_class').shadow().find('elix-input').eq(0).shadow().find('#inner').eq(0) - .type('svg_2_class{enter}', { force: true }); + .type('svg_2_class{enter}', { force: true }) cy.get('#svg_2') .should('satisfy', ($el) => { - const classList = Array.from($el[0].classList); - return classList.includes('svg_2_class'); - }); - }); + const classList = Array.from($el[0].classList) + return classList.includes('svg_2_class') + }) + }) it('check tool_polygon_change_id', function () { - cy.get('#svg_2').click({ force: true }).click({ force: true }); + cy.get('#svg_2').click({ force: true }).click({ force: true }) cy.get('#elem_id').shadow().find('elix-input').eq(0).shadow().find('#inner').eq(0) - .type('_id{enter}', { force: true }); + .type('_id{enter}', { force: true }) cy.get('#svg_2_id') .should('satisfy', ($el) => { - const classList = Array.from($el[0].classList); - return classList.includes('svg_2_class'); - }); - }); + const classList = Array.from($el[0].classList) + return classList.includes('svg_2_class') + }) + }) it('check tool_polygon_change_rotation', function () { - cy.get('#svg_2_id').click({ force: true }); - for(let n = 0; n < 5; n ++){ + cy.get('#svg_2_id').click({ force: true }) + for (let n = 0; n < 5; n++) { cy.get('#angle').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_polygon_change_blur', function () { - cy.get('#svg_2_id').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_2_id').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#blur').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_polygon_change_opacity', function () { - cy.get('#svg_2_id').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_2_id').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#opacity').shadow().find('elix-number-spin-box').eq(0).shadow().find('#downButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_polygon_bring_to_back', function () { - cy.get('#svg_2_id').click({ force: true }); - cy.get('#tool_move_bottom').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_2_id').click({ force: true }) + cy.get('#tool_move_bottom').click({ force: true }) + testSnapshot() + }) it('check tool_polygon_bring_to_front', function () { - cy.get('#svg_2_id').click({ force: true }); - cy.get('#tool_move_top').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_2_id').click({ force: true }) + cy.get('#tool_move_top').click({ force: true }) + testSnapshot() + }) it('check tool_polygon_delete', function () { - cy.get('#svg_2_id').click({ force: true }); - cy.get('#tool_delete').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_2_id').click({ force: true }) + cy.get('#tool_delete').click({ force: true }) + testSnapshot() + }) it('check tool_polygon_align_to_page', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#tool_position').shadow().find('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened'); + cy.get('#svg_1').click({ force: true }) + cy.get('#tool_position').shadow().find('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened') cy.get('#tool_position').find('se-list-item').eq(0).shadow().find('elix-option').eq(0) - .click({ force: true }); - testSnapshot(); - }); + .click({ force: true }) + testSnapshot() + }) /* it('check tool_polygon_change_x_y_coordinate', function () { cy.get('#svg_1').click({ force: true }); for(let n = 0; n < 25; n ++){ @@ -116,35 +116,35 @@ describe('use all parts of svg-edit', function () { testSnapshot(); }); */ it('check tool_polygon_change_stroke_width', function () { - cy.get('#svg_1').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_1').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#stroke_width').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_polygon_change_stoke_fill_color', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#stroke_color').shadow().find('#picker').eq(0).click({ force: true }); + cy.get('#svg_1').click({ force: true }) + cy.get('#stroke_color').shadow().find('#picker').eq(0).click({ force: true }) cy.get('#stroke_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('.QuickColor').eq(51).click({ force: true }); + .find('.QuickColor').eq(51).click({ force: true }) cy.get('#stroke_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('#Ok').eq(0).click({ force: true }); - cy.get('#fill_color').shadow().find('#picker').eq(0).click({ force: true }); + .find('#Ok').eq(0).click({ force: true }) + cy.get('#fill_color').shadow().find('#picker').eq(0).click({ force: true }) cy.get('#fill_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('.QuickColor').eq(3).click({ force: true }); + .find('.QuickColor').eq(3).click({ force: true }) cy.get('#fill_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('#Ok').eq(0).click({ force: true }); - testSnapshot(); - }); + .find('#Ok').eq(0).click({ force: true }) + testSnapshot() + }) it('check tool_polygon_change_sides', function () { - cy.get('#svg_1').click({ force: true }); + cy.get('#svg_1').click({ force: true }) cy.get('#polySides').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); - testSnapshot(); - }); -}); + .click({ force: true }) + testSnapshot() + }) +}) diff --git a/cypress/integration/ui/scenario7.js b/cypress/integration/ui/scenario7.js index f2925506..30886f6f 100644 --- a/cypress/integration/ui/scenario7.js +++ b/cypress/integration/ui/scenario7.js @@ -1,138 +1,138 @@ import { visitAndApproveStorage -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + cy.get('#svgcontent').cleanSnapshot() +} describe('use all parts of svg-edit', function () { before(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('check tool_source_set', function () { - cy.get('#tool_source').click({ force: true }); + cy.get('#tool_source').click({ force: true }) cy.get('#svg_source_textarea') .type('{selectall}', { force: true }) .type(` Layer 1 - `, { force: true, parseSpecialCharSequences: false }); - cy.get('#tool_source_save').click({ force: true }); - testSnapshot(); - }); + `, { force: true, parseSpecialCharSequences: false }) + cy.get('#tool_source_save').click({ force: true }) + testSnapshot() + }) it('check tool_star', function () { cy.get('#tool_star') - .click({ force: true }); + .click({ force: true }) cy.get('#svgcontent') .trigger('mousedown', 300, 150, { force: true }) .trigger('mousemove', 300, 250, { force: true }) - .trigger('mouseup', { force: true }); - testSnapshot(); - }); + .trigger('mouseup', { force: true }) + testSnapshot() + }) it('check tool_star_clone', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#tool_clone').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_1').click({ force: true }) + cy.get('#tool_clone').click({ force: true }) + testSnapshot() + }) it('check tool_star_change_class', function () { - cy.get('#svg_2').click({ force: true }); + cy.get('#svg_2').click({ force: true }) cy.get('#elem_class').shadow().find('elix-input').eq(0).shadow().find('#inner').eq(0) - .type('svg_2_class{enter}', { force: true }); + .type('svg_2_class{enter}', { force: true }) cy.get('#svg_2') .should('satisfy', ($el) => { - const classList = Array.from($el[0].classList); - return classList.includes('svg_2_class'); - }); - }); + const classList = Array.from($el[0].classList) + return classList.includes('svg_2_class') + }) + }) it('check tool_star_change_id', function () { - cy.get('#svg_2').click({ force: true }).click({ force: true }); + cy.get('#svg_2').click({ force: true }).click({ force: true }) cy.get('#elem_id').shadow().find('elix-input').eq(0).shadow().find('#inner').eq(0) - .type('_id{enter}', { force: true }); + .type('_id{enter}', { force: true }) cy.get('#svg_2_id') .should('satisfy', ($el) => { - const classList = Array.from($el[0].classList); - return classList.includes('svg_2_class'); - }); - }); + const classList = Array.from($el[0].classList) + return classList.includes('svg_2_class') + }) + }) it('check tool_star_change_rotation', function () { - cy.get('#svg_2_id').click({ force: true }); - for(let n = 0; n < 5; n ++){ + cy.get('#svg_2_id').click({ force: true }) + for (let n = 0; n < 5; n++) { cy.get('#angle').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_star_change_blur', function () { - cy.get('#svg_2_id').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_2_id').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#blur').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_star_change_opacity', function () { - cy.get('#svg_2_id').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_2_id').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#opacity').shadow().find('elix-number-spin-box').eq(0).shadow().find('#downButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_star_bring_to_back', function () { - cy.get('#svg_2_id').click({ force: true }); - cy.get('#tool_move_bottom').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_2_id').click({ force: true }) + cy.get('#tool_move_bottom').click({ force: true }) + testSnapshot() + }) it('check tool_star_bring_to_front', function () { - cy.get('#svg_2_id').click({ force: true }); - cy.get('#tool_move_top').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_2_id').click({ force: true }) + cy.get('#tool_move_top').click({ force: true }) + testSnapshot() + }) it('check tool_star_delete', function () { - cy.get('#svg_2_id').click({ force: true }); - cy.get('#tool_delete').click({ force: true }); - testSnapshot(); - }); + cy.get('#svg_2_id').click({ force: true }) + cy.get('#tool_delete').click({ force: true }) + testSnapshot() + }) it('check tool_star_align_to_page', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#tool_position').shadow().find('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened'); + cy.get('#svg_1').click({ force: true }) + cy.get('#tool_position').shadow().find('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened') cy.get('#tool_position').find('se-list-item').eq(0).shadow().find('elix-option').eq(0) - .click({ force: true }); - testSnapshot(); - }); + .click({ force: true }) + testSnapshot() + }) it('check tool_star_change_stroke_width', function () { - cy.get('#svg_1').click({ force: true }); - for(let n = 0; n < 10; n ++){ + cy.get('#svg_1').click({ force: true }) + for (let n = 0; n < 10; n++) { cy.get('#stroke_width').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); + .click({ force: true }) } - testSnapshot(); - }); + testSnapshot() + }) it('check tool_star_change_stoke_fill_color', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#stroke_color').shadow().find('#picker').eq(0).click({ force: true }); + cy.get('#svg_1').click({ force: true }) + cy.get('#stroke_color').shadow().find('#picker').eq(0).click({ force: true }) cy.get('#stroke_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('.QuickColor').eq(51).click({ force: true }); + .find('.QuickColor').eq(51).click({ force: true }) cy.get('#stroke_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('#Ok').eq(0).click({ force: true }); - cy.get('#fill_color').shadow().find('#picker').eq(0).click({ force: true }); + .find('#Ok').eq(0).click({ force: true }) + cy.get('#fill_color').shadow().find('#picker').eq(0).click({ force: true }) cy.get('#fill_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('.QuickColor').eq(3).click({ force: true }); + .find('.QuickColor').eq(3).click({ force: true }) cy.get('#fill_color').shadow().find('#color_picker').eq(0) .find('#jGraduate_colPick').eq(0).find('#jPicker-table').eq(0) - .find('#Ok').eq(0).click({ force: true }); - testSnapshot(); - }); + .find('#Ok').eq(0).click({ force: true }) + testSnapshot() + }) it('check tool_star_change_sides', function () { - cy.get('#svg_1').click({ force: true }); + cy.get('#svg_1').click({ force: true }) cy.get('#starNumPoints').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) - .click({ force: true }); - testSnapshot(); - }); -}); + .click({ force: true }) + testSnapshot() + }) +}) diff --git a/cypress/integration/ui/tool-selection.js b/cypress/integration/ui/tool-selection.js index c2e63289..98510bfe 100644 --- a/cypress/integration/ui/tool-selection.js +++ b/cypress/integration/ui/tool-selection.js @@ -1,17 +1,17 @@ import { visitAndApproveStorage -} from '../../support/ui-test-helper.js'; +} from '../../support/ui-test-helper.js' describe('UI - Tool selection', function () { beforeEach(() => { - visitAndApproveStorage(); - }); + visitAndApproveStorage() + }) it('should set rectangle selection by click', function () { cy.get('#tools_rect') - .should('not.have.attr', 'pressed'); + .should('not.have.attr', 'pressed') cy.get('#tools_rect') .trigger('click', { force: true }) - .should('have.attr', 'pressed'); - }); -}); + .should('have.attr', 'pressed') + }) +}) diff --git a/cypress/integration/unit/browser-bugs/removeItem-setAttribute.js b/cypress/integration/unit/browser-bugs/removeItem-setAttribute.js index 49648ebe..b7d68898 100644 --- a/cypress/integration/unit/browser-bugs/removeItem-setAttribute.js +++ b/cypress/integration/unit/browser-bugs/removeItem-setAttribute.js @@ -2,10 +2,10 @@ describe('Browser bugs', function () { it('removeItem and setAttribute test (Chromium 843901; now fixed)', function () { // See https://bugs.chromium.org/p/chromium/issues/detail?id=843901 - const elem = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); - elem.setAttribute('transform', 'matrix(1,0,0,1,0,0)'); - elem.transform.baseVal.removeItem(0); - elem.removeAttribute('transform'); - assert.equal(elem.hasAttribute('transform'), false); - }); -}); + const elem = document.createElementNS('http://www.w3.org/2000/svg', 'rect') + elem.setAttribute('transform', 'matrix(1,0,0,1,0,0)') + elem.transform.baseVal.removeItem(0) + elem.removeAttribute('transform') + assert.equal(elem.hasAttribute('transform'), false) + }) +}) diff --git a/cypress/integration/unit/contextmenu.js b/cypress/integration/unit/contextmenu.js index b906ebcf..6bc728fb 100644 --- a/cypress/integration/unit/contextmenu.js +++ b/cypress/integration/unit/contextmenu.js @@ -1,4 +1,4 @@ -import * as contextmenu from '../../../instrumented/editor/contextmenu.js'; +import * as contextmenu from '../../../instrumented/editor/contextmenu.js' describe('contextmenu', function () { /** @@ -6,53 +6,53 @@ describe('contextmenu', function () { * @returns {void} */ afterEach(() => { - contextmenu.resetCustomMenus(); - }); + contextmenu.resetCustomMenus() + }) it('Test svgedit.contextmenu package', function () { - assert.ok(contextmenu, 'contextmenu registered correctly'); - assert.ok(contextmenu.add, 'add registered correctly'); - assert.ok(contextmenu.hasCustomHandler, 'contextmenu hasCustomHandler registered correctly'); - assert.ok(contextmenu.getCustomHandler, 'contextmenu getCustomHandler registered correctly'); - }); + assert.ok(contextmenu, 'contextmenu registered correctly') + assert.ok(contextmenu.add, 'add registered correctly') + assert.ok(contextmenu.hasCustomHandler, 'contextmenu hasCustomHandler registered correctly') + assert.ok(contextmenu.getCustomHandler, 'contextmenu getCustomHandler registered correctly') + }) it('Test svgedit.contextmenu does not add invalid menu item', function () { assert.throws( () => contextmenu.add({ id: 'justanid' }), null, null, 'menu item with just an id is invalid' - ); + ) assert.throws( () => contextmenu.add({ id: 'idandlabel', label: 'anicelabel' }), null, null, 'menu item with just an id and label is invalid' - ); + ) assert.throws( () => contextmenu.add({ id: 'idandlabel', label: 'anicelabel', action: 'notafunction' }), null, null, 'menu item with action that is not a function is invalid' - ); - }); + ) + }) it('Test svgedit.contextmenu adds valid menu item', function () { - const validItem = { id: 'valid', label: 'anicelabel', action () { /* empty fn */ } }; - contextmenu.add(validItem); + const validItem = { id: 'valid', label: 'anicelabel', action () { /* empty fn */ } } + contextmenu.add(validItem) - assert.ok(contextmenu.hasCustomHandler('valid'), 'Valid menu item is added.'); - assert.equal(contextmenu.getCustomHandler('valid'), validItem.action, 'Valid menu action is added.'); - }); + assert.ok(contextmenu.hasCustomHandler('valid'), 'Valid menu item is added.') + assert.equal(contextmenu.getCustomHandler('valid'), validItem.action, 'Valid menu action is added.') + }) it('Test svgedit.contextmenu rejects valid duplicate menu item id', function () { - const validItem1 = { id: 'valid', label: 'anicelabel', action () { /* empty fn */ } }; - const validItem2 = { id: 'valid', label: 'anicelabel', action () { /* empty fn */ } }; - contextmenu.add(validItem1); + const validItem1 = { id: 'valid', label: 'anicelabel', action () { /* empty fn */ } } + const validItem2 = { id: 'valid', label: 'anicelabel', action () { /* empty fn */ } } + contextmenu.add(validItem1) assert.throws( () => contextmenu.add(validItem2), null, null, 'duplicate menu item is rejected.' - ); - }); -}); + ) + }) +}) diff --git a/cypress/integration/unit/coords.js b/cypress/integration/unit/coords.js index bee9e241..8b99e700 100644 --- a/cypress/integration/unit/coords.js +++ b/cypress/integration/unit/coords.js @@ -1,25 +1,25 @@ -import { NS } from '../../../instrumented/svgcanvas/namespaces.js'; -import * as utilities from '../../../instrumented/svgcanvas/utilities.js'; -import * as coords from '../../../instrumented/svgcanvas/coords.js'; +import { NS } from '../../../instrumented/svgcanvas/namespaces.js' +import * as utilities from '../../../instrumented/svgcanvas/utilities.js' +import * as coords from '../../../instrumented/svgcanvas/coords.js' describe('coords', function () { - let elemId = 1; + let elemId = 1 - const root = document.createElement('div'); - root.id = 'root'; - root.style.visibility = 'hidden'; - document.body.append(root); + const root = document.createElement('div') + root.id = 'root' + root.style.visibility = 'hidden' + document.body.append(root) /** * Set up tests with mock data. * @returns {void} */ beforeEach(function () { - const svgroot = document.createElementNS(NS.SVG, 'svg'); - svgroot.id = 'svgroot'; - root.append(svgroot); - this.svg = document.createElementNS(NS.SVG, 'svg'); - svgroot.append(this.svg); + const svgroot = document.createElementNS(NS.SVG, 'svg') + svgroot.id = 'svgroot' + root.append(svgroot) + this.svg = document.createElementNS(NS.SVG, 'svg') + svgroot.append(this.svg) // Mock out editor context. utilities.init( @@ -27,25 +27,25 @@ describe('coords', function () { * @implements {module:utilities.EditorContext} */ { - getSvgRoot: () => { return this.svg; }, - getDOMDocument () { return null; }, - getDOMContainer () { return null; } + getSvgRoot: () => { return this.svg }, + getDOMDocument () { return null }, + getDOMContainer () { return null } } - ); + ) coords.init( /** * @implements {module:coords.EditorContext} */ { - getGridSnapping () { return false; }, + getGridSnapping () { return false }, getDrawing () { return { - getNextId () { return String(elemId++); } - }; + getNextId () { return String(elemId++) } + } } } - ); - }); + ) + }) /** * Tear down tests, removing elements. @@ -53,255 +53,255 @@ describe('coords', function () { */ afterEach(function () { while (this.svg.hasChildNodes()) { - this.svg.firstChild.remove(); + this.svg.firstChild.remove() } - }); + }) it('Test remapElement(translate) for rect', function () { - const rect = document.createElementNS(NS.SVG, 'rect'); - rect.setAttribute('x', '200'); - rect.setAttribute('y', '150'); - rect.setAttribute('width', '250'); - rect.setAttribute('height', '120'); - this.svg.append(rect); + const rect = document.createElementNS(NS.SVG, 'rect') + rect.setAttribute('x', '200') + rect.setAttribute('y', '150') + rect.setAttribute('width', '250') + rect.setAttribute('height', '120') + this.svg.append(rect) const attrs = { x: '200', y: '150', width: '125', height: '75' - }; + } // Create a translate. - const m = this.svg.createSVGMatrix(); - m.a = 1; m.b = 0; - m.c = 0; m.d = 1; - m.e = 100; m.f = -50; + const m = this.svg.createSVGMatrix() + m.a = 1; m.b = 0 + m.c = 0; m.d = 1 + m.e = 100; m.f = -50 - coords.remapElement(rect, attrs, m); + coords.remapElement(rect, attrs, m) - assert.equal(rect.getAttribute('x'), '300'); - assert.equal(rect.getAttribute('y'), '100'); - assert.equal(rect.getAttribute('width'), '125'); - assert.equal(rect.getAttribute('height'), '75'); - }); + assert.equal(rect.getAttribute('x'), '300') + assert.equal(rect.getAttribute('y'), '100') + assert.equal(rect.getAttribute('width'), '125') + assert.equal(rect.getAttribute('height'), '75') + }) it('Test remapElement(scale) for rect', function () { - const rect = document.createElementNS(NS.SVG, 'rect'); - rect.setAttribute('width', '250'); - rect.setAttribute('height', '120'); - this.svg.append(rect); + const rect = document.createElementNS(NS.SVG, 'rect') + rect.setAttribute('width', '250') + rect.setAttribute('height', '120') + this.svg.append(rect) const attrs = { x: '0', y: '0', width: '250', height: '120' - }; + } // Create a translate. - const m = this.svg.createSVGMatrix(); - m.a = 2; m.b = 0; - m.c = 0; m.d = 0.5; - m.e = 0; m.f = 0; + const m = this.svg.createSVGMatrix() + m.a = 2; m.b = 0 + m.c = 0; m.d = 0.5 + m.e = 0; m.f = 0 - coords.remapElement(rect, attrs, m); + coords.remapElement(rect, attrs, m) - assert.equal(rect.getAttribute('x'), '0'); - assert.equal(rect.getAttribute('y'), '0'); - assert.equal(rect.getAttribute('width'), '500'); - assert.equal(rect.getAttribute('height'), '60'); - }); + assert.equal(rect.getAttribute('x'), '0') + assert.equal(rect.getAttribute('y'), '0') + assert.equal(rect.getAttribute('width'), '500') + assert.equal(rect.getAttribute('height'), '60') + }) it('Test remapElement(translate) for circle', function () { - const circle = document.createElementNS(NS.SVG, 'circle'); - circle.setAttribute('cx', '200'); - circle.setAttribute('cy', '150'); - circle.setAttribute('r', '125'); - this.svg.append(circle); + const circle = document.createElementNS(NS.SVG, 'circle') + circle.setAttribute('cx', '200') + circle.setAttribute('cy', '150') + circle.setAttribute('r', '125') + this.svg.append(circle) const attrs = { cx: '200', cy: '150', r: '125' - }; + } // Create a translate. - const m = this.svg.createSVGMatrix(); - m.a = 1; m.b = 0; - m.c = 0; m.d = 1; - m.e = 100; m.f = -50; + const m = this.svg.createSVGMatrix() + m.a = 1; m.b = 0 + m.c = 0; m.d = 1 + m.e = 100; m.f = -50 - coords.remapElement(circle, attrs, m); + coords.remapElement(circle, attrs, m) - assert.equal(circle.getAttribute('cx'), '300'); - assert.equal(circle.getAttribute('cy'), '100'); - assert.equal(circle.getAttribute('r'), '125'); - }); + assert.equal(circle.getAttribute('cx'), '300') + assert.equal(circle.getAttribute('cy'), '100') + assert.equal(circle.getAttribute('r'), '125') + }) it('Test remapElement(scale) for circle', function () { - const circle = document.createElementNS(NS.SVG, 'circle'); - circle.setAttribute('cx', '200'); - circle.setAttribute('cy', '150'); - circle.setAttribute('r', '250'); - this.svg.append(circle); + const circle = document.createElementNS(NS.SVG, 'circle') + circle.setAttribute('cx', '200') + circle.setAttribute('cy', '150') + circle.setAttribute('r', '250') + this.svg.append(circle) const attrs = { cx: '200', cy: '150', r: '250' - }; + } // Create a translate. - const m = this.svg.createSVGMatrix(); - m.a = 2; m.b = 0; - m.c = 0; m.d = 0.5; - m.e = 0; m.f = 0; + const m = this.svg.createSVGMatrix() + m.a = 2; m.b = 0 + m.c = 0; m.d = 0.5 + m.e = 0; m.f = 0 - coords.remapElement(circle, attrs, m); + coords.remapElement(circle, attrs, m) - assert.equal(circle.getAttribute('cx'), '400'); - assert.equal(circle.getAttribute('cy'), '75'); + assert.equal(circle.getAttribute('cx'), '400') + assert.equal(circle.getAttribute('cy'), '75') // Radius is the minimum that fits in the new bounding box. - assert.equal(circle.getAttribute('r'), '125'); - }); + assert.equal(circle.getAttribute('r'), '125') + }) it('Test remapElement(translate) for ellipse', function () { - const ellipse = document.createElementNS(NS.SVG, 'ellipse'); - ellipse.setAttribute('cx', '200'); - ellipse.setAttribute('cy', '150'); - ellipse.setAttribute('rx', '125'); - ellipse.setAttribute('ry', '75'); - this.svg.append(ellipse); + const ellipse = document.createElementNS(NS.SVG, 'ellipse') + ellipse.setAttribute('cx', '200') + ellipse.setAttribute('cy', '150') + ellipse.setAttribute('rx', '125') + ellipse.setAttribute('ry', '75') + this.svg.append(ellipse) const attrs = { cx: '200', cy: '150', rx: '125', ry: '75' - }; + } // Create a translate. - const m = this.svg.createSVGMatrix(); - m.a = 1; m.b = 0; - m.c = 0; m.d = 1; - m.e = 100; m.f = -50; + const m = this.svg.createSVGMatrix() + m.a = 1; m.b = 0 + m.c = 0; m.d = 1 + m.e = 100; m.f = -50 - coords.remapElement(ellipse, attrs, m); + coords.remapElement(ellipse, attrs, m) - assert.equal(ellipse.getAttribute('cx'), '300'); - assert.equal(ellipse.getAttribute('cy'), '100'); - assert.equal(ellipse.getAttribute('rx'), '125'); - assert.equal(ellipse.getAttribute('ry'), '75'); - }); + assert.equal(ellipse.getAttribute('cx'), '300') + assert.equal(ellipse.getAttribute('cy'), '100') + assert.equal(ellipse.getAttribute('rx'), '125') + assert.equal(ellipse.getAttribute('ry'), '75') + }) it('Test remapElement(scale) for ellipse', function () { - const ellipse = document.createElementNS(NS.SVG, 'ellipse'); - ellipse.setAttribute('cx', '200'); - ellipse.setAttribute('cy', '150'); - ellipse.setAttribute('rx', '250'); - ellipse.setAttribute('ry', '120'); - this.svg.append(ellipse); + const ellipse = document.createElementNS(NS.SVG, 'ellipse') + ellipse.setAttribute('cx', '200') + ellipse.setAttribute('cy', '150') + ellipse.setAttribute('rx', '250') + ellipse.setAttribute('ry', '120') + this.svg.append(ellipse) const attrs = { cx: '200', cy: '150', rx: '250', ry: '120' - }; + } // Create a translate. - const m = this.svg.createSVGMatrix(); - m.a = 2; m.b = 0; - m.c = 0; m.d = 0.5; - m.e = 0; m.f = 0; + const m = this.svg.createSVGMatrix() + m.a = 2; m.b = 0 + m.c = 0; m.d = 0.5 + m.e = 0; m.f = 0 - coords.remapElement(ellipse, attrs, m); + coords.remapElement(ellipse, attrs, m) - assert.equal(ellipse.getAttribute('cx'), '400'); - assert.equal(ellipse.getAttribute('cy'), '75'); - assert.equal(ellipse.getAttribute('rx'), '500'); - assert.equal(ellipse.getAttribute('ry'), '60'); - }); + assert.equal(ellipse.getAttribute('cx'), '400') + assert.equal(ellipse.getAttribute('cy'), '75') + assert.equal(ellipse.getAttribute('rx'), '500') + assert.equal(ellipse.getAttribute('ry'), '60') + }) it('Test remapElement(translate) for line', function () { - const line = document.createElementNS(NS.SVG, 'line'); - line.setAttribute('x1', '50'); - line.setAttribute('y1', '100'); - line.setAttribute('x2', '120'); - line.setAttribute('y2', '200'); - this.svg.append(line); + const line = document.createElementNS(NS.SVG, 'line') + line.setAttribute('x1', '50') + line.setAttribute('y1', '100') + line.setAttribute('x2', '120') + line.setAttribute('y2', '200') + this.svg.append(line) const attrs = { x1: '50', y1: '100', x2: '120', y2: '200' - }; + } // Create a translate. - const m = this.svg.createSVGMatrix(); - m.a = 1; m.b = 0; - m.c = 0; m.d = 1; - m.e = 100; m.f = -50; + const m = this.svg.createSVGMatrix() + m.a = 1; m.b = 0 + m.c = 0; m.d = 1 + m.e = 100; m.f = -50 - coords.remapElement(line, attrs, m); + coords.remapElement(line, attrs, m) - assert.equal(line.getAttribute('x1'), '150'); - assert.equal(line.getAttribute('y1'), '50'); - assert.equal(line.getAttribute('x2'), '220'); - assert.equal(line.getAttribute('y2'), '150'); - }); + assert.equal(line.getAttribute('x1'), '150') + assert.equal(line.getAttribute('y1'), '50') + assert.equal(line.getAttribute('x2'), '220') + assert.equal(line.getAttribute('y2'), '150') + }) it('Test remapElement(scale) for line', function () { - const line = document.createElementNS(NS.SVG, 'line'); - line.setAttribute('x1', '50'); - line.setAttribute('y1', '100'); - line.setAttribute('x2', '120'); - line.setAttribute('y2', '200'); - this.svg.append(line); + const line = document.createElementNS(NS.SVG, 'line') + line.setAttribute('x1', '50') + line.setAttribute('y1', '100') + line.setAttribute('x2', '120') + line.setAttribute('y2', '200') + this.svg.append(line) const attrs = { x1: '50', y1: '100', x2: '120', y2: '200' - }; + } // Create a translate. - const m = this.svg.createSVGMatrix(); - m.a = 2; m.b = 0; - m.c = 0; m.d = 0.5; - m.e = 0; m.f = 0; + const m = this.svg.createSVGMatrix() + m.a = 2; m.b = 0 + m.c = 0; m.d = 0.5 + m.e = 0; m.f = 0 - coords.remapElement(line, attrs, m); + coords.remapElement(line, attrs, m) - assert.equal(line.getAttribute('x1'), '100'); - assert.equal(line.getAttribute('y1'), '50'); - assert.equal(line.getAttribute('x2'), '240'); - assert.equal(line.getAttribute('y2'), '100'); - }); + assert.equal(line.getAttribute('x1'), '100') + assert.equal(line.getAttribute('y1'), '50') + assert.equal(line.getAttribute('x2'), '240') + assert.equal(line.getAttribute('y2'), '100') + }) it('Test remapElement(translate) for text', function () { - const text = document.createElementNS(NS.SVG, 'text'); - text.setAttribute('x', '50'); - text.setAttribute('y', '100'); - this.svg.append(text); + const text = document.createElementNS(NS.SVG, 'text') + text.setAttribute('x', '50') + text.setAttribute('y', '100') + this.svg.append(text) const attrs = { x: '50', y: '100' - }; + } // Create a translate. - const m = this.svg.createSVGMatrix(); - m.a = 1; m.b = 0; - m.c = 0; m.d = 1; - m.e = 100; m.f = -50; + const m = this.svg.createSVGMatrix() + m.a = 1; m.b = 0 + m.c = 0; m.d = 1 + m.e = 100; m.f = -50 - coords.remapElement(text, attrs, m); + coords.remapElement(text, attrs, m) - assert.equal(text.getAttribute('x'), '150'); - assert.equal(text.getAttribute('y'), '50'); - }); -}); + assert.equal(text.getAttribute('x'), '150') + assert.equal(text.getAttribute('y'), '50') + }) +}) diff --git a/cypress/integration/unit/draw.js b/cypress/integration/unit/draw.js index 17fb5850..411fa8f2 100644 --- a/cypress/integration/unit/draw.js +++ b/cypress/integration/unit/draw.js @@ -1,21 +1,21 @@ -import 'pathseg'; -import { NS } from '../../../instrumented/svgcanvas/namespaces.js'; -import * as draw from '../../../instrumented/svgcanvas/draw.js'; -import * as units from '../../../instrumented/common/units.js'; +import 'pathseg' +import { NS } from '../../../instrumented/svgcanvas/namespaces.js' +import * as draw from '../../../instrumented/svgcanvas/draw.js' +import * as units from '../../../instrumented/common/units.js' describe('draw.Drawing', function () { const addOwnSpies = (obj) => { - const methods = Object.keys(obj); + const methods = Object.keys(obj) methods.forEach((method) => { - cy.spy(obj, method); - }); - }; + cy.spy(obj, method) + }) + } - const LAYER_CLASS = draw.Layer.CLASS_NAME; - const NONCE = 'foo'; - const LAYER1 = 'Layer 1'; - const LAYER2 = 'Layer 2'; - const LAYER3 = 'Layer 3'; + const LAYER_CLASS = draw.Layer.CLASS_NAME + const NONCE = 'foo' + const LAYER1 = 'Layer 1' + const LAYER2 = 'Layer 2' + const LAYER3 = 'Layer 3' const PATH_ATTR = { // clone will convert relative to absolute, so the test for equality fails. // d: 'm7.38867,57.38867c0,-27.62431 22.37569,-50 50,-50c27.62431,0 50,22.37569 50,50c0,27.62431 -22.37569,50 -50,50c-27.62431,0 -50,-22.37569 -50,-50z', @@ -24,7 +24,7 @@ describe('draw.Drawing', function () { 'stroke-width': '5', stroke: '#660000', fill: '#ff0000' - }; + } units.init( /** @@ -32,17 +32,17 @@ describe('draw.Drawing', function () { */ { // used by units.shortFloat - call path: cloneLayer -> copyElem -> convertPath -> pathDSegment -> shortFloat - getRoundDigits () { return 3; } + getRoundDigits () { return 3 } } - ); + ) // Simplifying from svgcanvas.js usage - const idprefix = 'svg_'; + const idprefix = 'svg_' const getCurrentDrawing = function () { - return currentDrawing_; - }; - const setCurrentGroup = () => { /* empty fn */ }; + return currentDrawing_ + } + const setCurrentGroup = () => { /* empty fn */ } draw.init( /** * @implements {module:draw.DrawCanvasInit} @@ -51,41 +51,41 @@ describe('draw.Drawing', function () { getCurrentDrawing, setCurrentGroup } - ); + ) /** * @param {module:utilities.SVGElementJSON} jsonMap * @returns {SVGElement} */ function createSVGElement (jsonMap) { - const elem = document.createElementNS(NS.SVG, jsonMap.element); - Object.entries(jsonMap.attr).forEach(([ attr, value ]) => { - elem.setAttribute(attr, value); - }); - return elem; + const elem = document.createElementNS(NS.SVG, jsonMap.element) + Object.entries(jsonMap.attr).forEach(([attr, value]) => { + elem.setAttribute(attr, value) + }) + return elem } const setupSVGWith3Layers = function (svgElem) { - const layer1 = document.createElementNS(NS.SVG, 'g'); - const layer1Title = document.createElementNS(NS.SVG, 'title'); - layer1Title.append(LAYER1); - layer1.append(layer1Title); - svgElem.append(layer1); + const layer1 = document.createElementNS(NS.SVG, 'g') + const layer1Title = document.createElementNS(NS.SVG, 'title') + layer1Title.append(LAYER1) + layer1.append(layer1Title) + svgElem.append(layer1) - const layer2 = document.createElementNS(NS.SVG, 'g'); - const layer2Title = document.createElementNS(NS.SVG, 'title'); - layer2Title.append(LAYER2); - layer2.append(layer2Title); - svgElem.append(layer2); + const layer2 = document.createElementNS(NS.SVG, 'g') + const layer2Title = document.createElementNS(NS.SVG, 'title') + layer2Title.append(LAYER2) + layer2.append(layer2Title) + svgElem.append(layer2) - const layer3 = document.createElementNS(NS.SVG, 'g'); - const layer3Title = document.createElementNS(NS.SVG, 'title'); - layer3Title.append(LAYER3); - layer3.append(layer3Title); - svgElem.append(layer3); + const layer3 = document.createElementNS(NS.SVG, 'g') + const layer3Title = document.createElementNS(NS.SVG, 'title') + layer3Title.append(LAYER3) + layer3.append(layer3Title) + svgElem.append(layer3) - return [ layer1, layer2, layer3 ]; - }; + return [layer1, layer2, layer3] + } const createSomeElementsInGroup = function (group) { group.append( @@ -105,399 +105,399 @@ describe('draw.Drawing', function () { element: 'line', attr: { x1: '0', y1: '1', x2: '5', y2: '6' } }) - ); + ) const g = createSVGElement({ element: 'g', attr: {} - }); + }) g.append(createSVGElement({ element: 'rect', attr: { x: '0', y: '1', width: '5', height: '10' } - })); - group.append(g); - return 4; - }; + })) + group.append(g) + return 4 + } const cleanupSVG = function (svgElem) { - while (svgElem.firstChild) { svgElem.firstChild.remove(); } - }; + while (svgElem.firstChild) { svgElem.firstChild.remove() } + } - let sandbox; let currentDrawing_; let svg; let svgN; + let sandbox; let currentDrawing_; let svg; let svgN beforeEach(() => { - sandbox = document.createElement('div'); - sandbox.id = 'sandbox'; - sandbox.style.visibility = 'hidden'; + sandbox = document.createElement('div') + sandbox.id = 'sandbox' + sandbox.style.visibility = 'hidden' - svg = document.createElementNS(NS.SVG, 'svg'); + svg = document.createElementNS(NS.SVG, 'svg') // Firefox throws exception in getBBox() when svg is not attached to DOM. - sandbox.append(svg); + sandbox.append(svg) // Set up with nonce. - svgN = document.createElementNS(NS.SVG, 'svg'); - svgN.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE); - svgN.setAttributeNS(NS.SE, 'se:nonce', NONCE); + svgN = document.createElementNS(NS.SVG, 'svg') + svgN.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE) + svgN.setAttributeNS(NS.SE, 'se:nonce', NONCE) - const svgContent = document.createElementNS(NS.SVG, 'svg'); - currentDrawing_ = new draw.Drawing(svgContent, idprefix); - }); + const svgContent = document.createElementNS(NS.SVG, 'svg') + currentDrawing_ = new draw.Drawing(svgContent, idprefix) + }) it('Test draw module', function () { - assert.ok(draw); - assert.equal(typeof draw, typeof {}); + assert.ok(draw) + assert.equal(typeof draw, typeof {}) - assert.ok(draw.Drawing); - assert.equal(typeof draw.Drawing, typeof function () { /* empty fn */ }); - }); + assert.ok(draw.Drawing) + assert.equal(typeof draw.Drawing, typeof function () { /* empty fn */ }) + }) it('Test document creation', function () { - let doc; + let doc try { - doc = new draw.Drawing(); - assert.ok(false, 'Created drawing without a valid element'); + doc = new draw.Drawing() + assert.ok(false, 'Created drawing without a valid element') } catch (e) { - assert.ok(true); + assert.ok(true) } try { - doc = new draw.Drawing(svg); - assert.ok(doc); - assert.equal(typeof doc, typeof {}); + doc = new draw.Drawing(svg) + assert.ok(doc) + assert.equal(typeof doc, typeof {}) } catch (e) { - assert.ok(false, 'Could not create document from valid element: ' + e); + assert.ok(false, 'Could not create document from valid element: ' + e) } - }); + }) it('Test nonce', function () { - let doc = new draw.Drawing(svg); - assert.equal(doc.getNonce(), ''); + let doc = new draw.Drawing(svg) + assert.equal(doc.getNonce(), '') - doc = new draw.Drawing(svgN); - assert.equal(doc.getNonce(), NONCE); - assert.equal(doc.getSvgElem().getAttributeNS(NS.SE, 'nonce'), NONCE); + doc = new draw.Drawing(svgN) + assert.equal(doc.getNonce(), NONCE) + assert.equal(doc.getSvgElem().getAttributeNS(NS.SE, 'nonce'), NONCE) - doc.clearNonce(); - assert.ok(!doc.getNonce()); - assert.ok(!doc.getSvgElem().getAttributeNS(NS.SE, 'se:nonce')); + doc.clearNonce() + assert.ok(!doc.getNonce()) + assert.ok(!doc.getSvgElem().getAttributeNS(NS.SE, 'se:nonce')) - doc.setNonce(NONCE); - assert.equal(doc.getNonce(), NONCE); - assert.equal(doc.getSvgElem().getAttributeNS(NS.SE, 'nonce'), NONCE); - }); + doc.setNonce(NONCE) + assert.equal(doc.getNonce(), NONCE) + assert.equal(doc.getSvgElem().getAttributeNS(NS.SE, 'nonce'), NONCE) + }) it('Test getId() and getNextId() without nonce', function () { - const elem2 = document.createElementNS(NS.SVG, 'circle'); - elem2.id = 'svg_2'; - svg.append(elem2); + const elem2 = document.createElementNS(NS.SVG, 'circle') + elem2.id = 'svg_2' + svg.append(elem2) - const doc = new draw.Drawing(svg); + const doc = new draw.Drawing(svg) - assert.equal(doc.getId(), 'svg_0'); + assert.equal(doc.getId(), 'svg_0') - assert.equal(doc.getNextId(), 'svg_1'); - assert.equal(doc.getId(), 'svg_1'); + assert.equal(doc.getNextId(), 'svg_1') + assert.equal(doc.getId(), 'svg_1') - assert.equal(doc.getNextId(), 'svg_3'); - assert.equal(doc.getId(), 'svg_3'); + assert.equal(doc.getNextId(), 'svg_3') + assert.equal(doc.getId(), 'svg_3') - assert.equal(doc.getNextId(), 'svg_4'); - assert.equal(doc.getId(), 'svg_4'); + assert.equal(doc.getNextId(), 'svg_4') + assert.equal(doc.getId(), 'svg_4') // clean out svg document - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test getId() and getNextId() with prefix without nonce', function () { - const prefix = 'Bar-'; - const doc = new draw.Drawing(svg, prefix); + const prefix = 'Bar-' + const doc = new draw.Drawing(svg, prefix) - assert.equal(doc.getId(), prefix + '0'); + assert.equal(doc.getId(), prefix + '0') - assert.equal(doc.getNextId(), prefix + '1'); - assert.equal(doc.getId(), prefix + '1'); + assert.equal(doc.getNextId(), prefix + '1') + assert.equal(doc.getId(), prefix + '1') - assert.equal(doc.getNextId(), prefix + '2'); - assert.equal(doc.getId(), prefix + '2'); + assert.equal(doc.getNextId(), prefix + '2') + assert.equal(doc.getId(), prefix + '2') - assert.equal(doc.getNextId(), prefix + '3'); - assert.equal(doc.getId(), prefix + '3'); + assert.equal(doc.getNextId(), prefix + '3') + assert.equal(doc.getId(), prefix + '3') - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test getId() and getNextId() with nonce', function () { - const prefix = 'svg_' + NONCE; + const prefix = 'svg_' + NONCE - const elem2 = document.createElementNS(NS.SVG, 'circle'); - elem2.id = prefix + '_2'; - svgN.append(elem2); + const elem2 = document.createElementNS(NS.SVG, 'circle') + elem2.id = prefix + '_2' + svgN.append(elem2) - const doc = new draw.Drawing(svgN); + const doc = new draw.Drawing(svgN) - assert.equal(doc.getId(), prefix + '_0'); + assert.equal(doc.getId(), prefix + '_0') - assert.equal(doc.getNextId(), prefix + '_1'); - assert.equal(doc.getId(), prefix + '_1'); + assert.equal(doc.getNextId(), prefix + '_1') + assert.equal(doc.getId(), prefix + '_1') - assert.equal(doc.getNextId(), prefix + '_3'); - assert.equal(doc.getId(), prefix + '_3'); + assert.equal(doc.getNextId(), prefix + '_3') + assert.equal(doc.getId(), prefix + '_3') - assert.equal(doc.getNextId(), prefix + '_4'); - assert.equal(doc.getId(), prefix + '_4'); + assert.equal(doc.getNextId(), prefix + '_4') + assert.equal(doc.getId(), prefix + '_4') - cleanupSVG(svgN); - }); + cleanupSVG(svgN) + }) it('Test getId() and getNextId() with prefix with nonce', function () { - const PREFIX = 'Bar-'; - const doc = new draw.Drawing(svgN, PREFIX); + const PREFIX = 'Bar-' + const doc = new draw.Drawing(svgN, PREFIX) - const prefix = PREFIX + NONCE + '_'; - assert.equal(doc.getId(), prefix + '0'); + const prefix = PREFIX + NONCE + '_' + assert.equal(doc.getId(), prefix + '0') - assert.equal(doc.getNextId(), prefix + '1'); - assert.equal(doc.getId(), prefix + '1'); + assert.equal(doc.getNextId(), prefix + '1') + assert.equal(doc.getId(), prefix + '1') - assert.equal(doc.getNextId(), prefix + '2'); - assert.equal(doc.getId(), prefix + '2'); + assert.equal(doc.getNextId(), prefix + '2') + assert.equal(doc.getId(), prefix + '2') - assert.equal(doc.getNextId(), prefix + '3'); - assert.equal(doc.getId(), prefix + '3'); + assert.equal(doc.getNextId(), prefix + '3') + assert.equal(doc.getId(), prefix + '3') - cleanupSVG(svgN); - }); + cleanupSVG(svgN) + }) it('Test releaseId()', function () { - const doc = new draw.Drawing(svg); + const doc = new draw.Drawing(svg) - const firstId = doc.getNextId(); - /* const secondId = */ doc.getNextId(); + const firstId = doc.getNextId() + /* const secondId = */ doc.getNextId() - const result = doc.releaseId(firstId); - assert.ok(result); - assert.equal(doc.getNextId(), firstId); - assert.equal(doc.getNextId(), 'svg_3'); + const result = doc.releaseId(firstId) + assert.ok(result) + assert.equal(doc.getNextId(), firstId) + assert.equal(doc.getNextId(), 'svg_3') - assert.ok(!doc.releaseId('bad-id')); - assert.ok(doc.releaseId(firstId)); - assert.ok(!doc.releaseId(firstId)); + assert.ok(!doc.releaseId('bad-id')) + assert.ok(doc.releaseId(firstId)) + assert.ok(!doc.releaseId(firstId)) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test getNumLayers', function () { - const drawing = new draw.Drawing(svg); - assert.equal(typeof drawing.getNumLayers, typeof function () { /* empty fn */ }); - assert.equal(drawing.getNumLayers(), 0); + const drawing = new draw.Drawing(svg) + assert.equal(typeof drawing.getNumLayers, typeof function () { /* empty fn */ }) + assert.equal(drawing.getNumLayers(), 0) - setupSVGWith3Layers(svg); - drawing.identifyLayers(); + setupSVGWith3Layers(svg) + drawing.identifyLayers() - assert.equal(drawing.getNumLayers(), 3); + assert.equal(drawing.getNumLayers(), 3) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test hasLayer', function () { - setupSVGWith3Layers(svg); - const drawing = new draw.Drawing(svg); - drawing.identifyLayers(); + setupSVGWith3Layers(svg) + const drawing = new draw.Drawing(svg) + drawing.identifyLayers() - assert.equal(typeof drawing.hasLayer, typeof function () { /* empty fn */ }); - assert.ok(!drawing.hasLayer('invalid-layer')); + assert.equal(typeof drawing.hasLayer, typeof function () { /* empty fn */ }) + assert.ok(!drawing.hasLayer('invalid-layer')) - assert.ok(drawing.hasLayer(LAYER3)); - assert.ok(drawing.hasLayer(LAYER2)); - assert.ok(drawing.hasLayer(LAYER1)); + assert.ok(drawing.hasLayer(LAYER3)) + assert.ok(drawing.hasLayer(LAYER2)) + assert.ok(drawing.hasLayer(LAYER1)) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test identifyLayers() with empty document', function () { - const drawing = new draw.Drawing(svg); - assert.equal(drawing.getCurrentLayer(), null); + const drawing = new draw.Drawing(svg) + assert.equal(drawing.getCurrentLayer(), null) // By default, an empty document gets an empty group created. - drawing.identifyLayers(); + drawing.identifyLayers() // Check that element now has one child node - assert.ok(drawing.getSvgElem().hasChildNodes()); - assert.equal(drawing.getSvgElem().childNodes.length, 1); + assert.ok(drawing.getSvgElem().hasChildNodes()) + assert.equal(drawing.getSvgElem().childNodes.length, 1) // Check that all_layers are correctly set up. - assert.equal(drawing.getNumLayers(), 1); - const emptyLayer = drawing.all_layers[0]; - assert.ok(emptyLayer); - const layerGroup = emptyLayer.getGroup(); - assert.equal(layerGroup, drawing.getSvgElem().firstChild); - assert.equal(layerGroup.tagName, 'g'); - assert.equal(layerGroup.getAttribute('class'), LAYER_CLASS); - assert.ok(layerGroup.hasChildNodes()); - assert.equal(layerGroup.childNodes.length, 1); - const firstChild = layerGroup.childNodes.item(0); - assert.equal(firstChild.tagName, 'title'); + assert.equal(drawing.getNumLayers(), 1) + const emptyLayer = drawing.all_layers[0] + assert.ok(emptyLayer) + const layerGroup = emptyLayer.getGroup() + assert.equal(layerGroup, drawing.getSvgElem().firstChild) + assert.equal(layerGroup.tagName, 'g') + assert.equal(layerGroup.getAttribute('class'), LAYER_CLASS) + assert.ok(layerGroup.hasChildNodes()) + assert.equal(layerGroup.childNodes.length, 1) + const firstChild = layerGroup.childNodes.item(0) + assert.equal(firstChild.tagName, 'title') - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test identifyLayers() with some layers', function () { - const drawing = new draw.Drawing(svg); - setupSVGWith3Layers(svg); + const drawing = new draw.Drawing(svg) + setupSVGWith3Layers(svg) - assert.equal(svg.childNodes.length, 3); + assert.equal(svg.childNodes.length, 3) - drawing.identifyLayers(); + drawing.identifyLayers() - assert.equal(drawing.getNumLayers(), 3); - assert.equal(drawing.all_layers[0].getGroup(), svg.childNodes.item(0)); - assert.equal(drawing.all_layers[1].getGroup(), svg.childNodes.item(1)); - assert.equal(drawing.all_layers[2].getGroup(), svg.childNodes.item(2)); + assert.equal(drawing.getNumLayers(), 3) + assert.equal(drawing.all_layers[0].getGroup(), svg.childNodes.item(0)) + assert.equal(drawing.all_layers[1].getGroup(), svg.childNodes.item(1)) + assert.equal(drawing.all_layers[2].getGroup(), svg.childNodes.item(2)) - assert.equal(drawing.all_layers[0].getGroup().getAttribute('class'), LAYER_CLASS); - assert.equal(drawing.all_layers[1].getGroup().getAttribute('class'), LAYER_CLASS); - assert.equal(drawing.all_layers[2].getGroup().getAttribute('class'), LAYER_CLASS); + assert.equal(drawing.all_layers[0].getGroup().getAttribute('class'), LAYER_CLASS) + assert.equal(drawing.all_layers[1].getGroup().getAttribute('class'), LAYER_CLASS) + assert.equal(drawing.all_layers[2].getGroup().getAttribute('class'), LAYER_CLASS) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test identifyLayers() with some layers and orphans', function () { - setupSVGWith3Layers(svg); + setupSVGWith3Layers(svg) - const orphan1 = document.createElementNS(NS.SVG, 'rect'); - const orphan2 = document.createElementNS(NS.SVG, 'rect'); - svg.append(orphan1, orphan2); + const orphan1 = document.createElementNS(NS.SVG, 'rect') + const orphan2 = document.createElementNS(NS.SVG, 'rect') + svg.append(orphan1, orphan2) - assert.equal(svg.childNodes.length, 5); + assert.equal(svg.childNodes.length, 5) - const drawing = new draw.Drawing(svg); - drawing.identifyLayers(); + const drawing = new draw.Drawing(svg) + drawing.identifyLayers() - assert.equal(drawing.getNumLayers(), 4); - assert.equal(drawing.all_layers[0].getGroup(), svg.childNodes.item(0)); - assert.equal(drawing.all_layers[1].getGroup(), svg.childNodes.item(1)); - assert.equal(drawing.all_layers[2].getGroup(), svg.childNodes.item(2)); - assert.equal(drawing.all_layers[3].getGroup(), svg.childNodes.item(3)); + assert.equal(drawing.getNumLayers(), 4) + assert.equal(drawing.all_layers[0].getGroup(), svg.childNodes.item(0)) + assert.equal(drawing.all_layers[1].getGroup(), svg.childNodes.item(1)) + assert.equal(drawing.all_layers[2].getGroup(), svg.childNodes.item(2)) + assert.equal(drawing.all_layers[3].getGroup(), svg.childNodes.item(3)) - assert.equal(drawing.all_layers[0].getGroup().getAttribute('class'), LAYER_CLASS); - assert.equal(drawing.all_layers[1].getGroup().getAttribute('class'), LAYER_CLASS); - assert.equal(drawing.all_layers[2].getGroup().getAttribute('class'), LAYER_CLASS); - assert.equal(drawing.all_layers[3].getGroup().getAttribute('class'), LAYER_CLASS); + assert.equal(drawing.all_layers[0].getGroup().getAttribute('class'), LAYER_CLASS) + assert.equal(drawing.all_layers[1].getGroup().getAttribute('class'), LAYER_CLASS) + assert.equal(drawing.all_layers[2].getGroup().getAttribute('class'), LAYER_CLASS) + assert.equal(drawing.all_layers[3].getGroup().getAttribute('class'), LAYER_CLASS) - const layer4 = drawing.all_layers[3].getGroup(); - assert.equal(layer4.tagName, 'g'); - assert.equal(layer4.childNodes.length, 3); - assert.equal(layer4.childNodes.item(1), orphan1); - assert.equal(layer4.childNodes.item(2), orphan2); + const layer4 = drawing.all_layers[3].getGroup() + assert.equal(layer4.tagName, 'g') + assert.equal(layer4.childNodes.length, 3) + assert.equal(layer4.childNodes.item(1), orphan1) + assert.equal(layer4.childNodes.item(2), orphan2) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test getLayerName()', function () { - const drawing = new draw.Drawing(svg); - setupSVGWith3Layers(svg); + const drawing = new draw.Drawing(svg) + setupSVGWith3Layers(svg) - drawing.identifyLayers(); + drawing.identifyLayers() - assert.equal(drawing.getNumLayers(), 3); - assert.equal(drawing.getLayerName(0), LAYER1); - assert.equal(drawing.getLayerName(1), LAYER2); - assert.equal(drawing.getLayerName(2), LAYER3); + assert.equal(drawing.getNumLayers(), 3) + assert.equal(drawing.getLayerName(0), LAYER1) + assert.equal(drawing.getLayerName(1), LAYER2) + assert.equal(drawing.getLayerName(2), LAYER3) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test getCurrentLayer()', function () { - const drawing = new draw.Drawing(svg); - setupSVGWith3Layers(svg); - drawing.identifyLayers(); + const drawing = new draw.Drawing(svg) + setupSVGWith3Layers(svg) + drawing.identifyLayers() - assert.ok(drawing.getCurrentLayer); - assert.equal(typeof drawing.getCurrentLayer, typeof function () { /* empty fn */ }); - assert.ok(drawing.getCurrentLayer()); - assert.equal(drawing.getCurrentLayer(), drawing.all_layers[2].getGroup()); + assert.ok(drawing.getCurrentLayer) + assert.equal(typeof drawing.getCurrentLayer, typeof function () { /* empty fn */ }) + assert.ok(drawing.getCurrentLayer()) + assert.equal(drawing.getCurrentLayer(), drawing.all_layers[2].getGroup()) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test setCurrentLayer() and getCurrentLayerName()', function () { - const drawing = new draw.Drawing(svg); - setupSVGWith3Layers(svg); - drawing.identifyLayers(); + const drawing = new draw.Drawing(svg) + setupSVGWith3Layers(svg) + drawing.identifyLayers() - assert.ok(drawing.setCurrentLayer); - assert.equal(typeof drawing.setCurrentLayer, typeof function () { /* empty fn */ }); + assert.ok(drawing.setCurrentLayer) + assert.equal(typeof drawing.setCurrentLayer, typeof function () { /* empty fn */ }) - drawing.setCurrentLayer(LAYER2); - assert.equal(drawing.getCurrentLayerName(), LAYER2); - assert.equal(drawing.getCurrentLayer(), drawing.all_layers[1].getGroup()); + drawing.setCurrentLayer(LAYER2) + assert.equal(drawing.getCurrentLayerName(), LAYER2) + assert.equal(drawing.getCurrentLayer(), drawing.all_layers[1].getGroup()) - drawing.setCurrentLayer(LAYER3); - assert.equal(drawing.getCurrentLayerName(), LAYER3); - assert.equal(drawing.getCurrentLayer(), drawing.all_layers[2].getGroup()); + drawing.setCurrentLayer(LAYER3) + assert.equal(drawing.getCurrentLayerName(), LAYER3) + assert.equal(drawing.getCurrentLayer(), drawing.all_layers[2].getGroup()) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test setCurrentLayerName()', function () { const mockHrService = { changeElement () { // empty } - }; - addOwnSpies(mockHrService); + } + addOwnSpies(mockHrService) - const drawing = new draw.Drawing(svg); - setupSVGWith3Layers(svg); - drawing.identifyLayers(); + const drawing = new draw.Drawing(svg) + setupSVGWith3Layers(svg) + drawing.identifyLayers() - assert.ok(drawing.setCurrentLayerName); - assert.equal(typeof drawing.setCurrentLayerName, typeof function () { /* empty fn */ }); + assert.ok(drawing.setCurrentLayerName) + assert.equal(typeof drawing.setCurrentLayerName, typeof function () { /* empty fn */ }) - const oldName = drawing.getCurrentLayerName(); - const newName = 'New Name'; - assert.ok(drawing.layer_map[oldName]); - assert.equal(drawing.layer_map[newName], undefined); // newName shouldn't exist. - const result = drawing.setCurrentLayerName(newName, mockHrService); - assert.equal(result, newName); - assert.equal(drawing.getCurrentLayerName(), newName); + const oldName = drawing.getCurrentLayerName() + const newName = 'New Name' + assert.ok(drawing.layer_map[oldName]) + assert.equal(drawing.layer_map[newName], undefined) // newName shouldn't exist. + const result = drawing.setCurrentLayerName(newName, mockHrService) + assert.equal(result, newName) + assert.equal(drawing.getCurrentLayerName(), newName) // Was the map updated? - assert.equal(drawing.layer_map[oldName], undefined); - assert.equal(drawing.layer_map[newName], drawing.current_layer); + assert.equal(drawing.layer_map[oldName], undefined) + assert.equal(drawing.layer_map[newName], drawing.current_layer) // Was mockHrService called? - assert.ok(mockHrService.changeElement.calledOnce); - assert.equal(oldName, mockHrService.changeElement.getCall(0).args[1]['#text']); - assert.equal(newName, mockHrService.changeElement.getCall(0).args[0].textContent); + assert.ok(mockHrService.changeElement.calledOnce) + assert.equal(oldName, mockHrService.changeElement.getCall(0).args[1]['#text']) + assert.equal(newName, mockHrService.changeElement.getCall(0).args[0].textContent) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test createLayer()', function () { const mockHrService = { startBatchCommand () { /* empty fn */ }, endBatchCommand () { /* empty fn */ }, insertElement () { /* empty fn */ } - }; - addOwnSpies(mockHrService); + } + addOwnSpies(mockHrService) - const drawing = new draw.Drawing(svg); - setupSVGWith3Layers(svg); - drawing.identifyLayers(); + const drawing = new draw.Drawing(svg) + setupSVGWith3Layers(svg) + drawing.identifyLayers() - assert.ok(drawing.createLayer); - assert.equal(typeof drawing.createLayer, typeof function () { /* empty fn */ }); + assert.ok(drawing.createLayer) + assert.equal(typeof drawing.createLayer, typeof function () { /* empty fn */ }) - const NEW_LAYER_NAME = 'Layer A'; - const layerG = drawing.createLayer(NEW_LAYER_NAME, mockHrService); - assert.equal(drawing.getNumLayers(), 4); - assert.equal(layerG, drawing.getCurrentLayer()); - assert.equal(layerG.getAttribute('class'), LAYER_CLASS); - assert.equal(NEW_LAYER_NAME, drawing.getCurrentLayerName()); - assert.equal(NEW_LAYER_NAME, drawing.getLayerName(3)); + const NEW_LAYER_NAME = 'Layer A' + const layerG = drawing.createLayer(NEW_LAYER_NAME, mockHrService) + assert.equal(drawing.getNumLayers(), 4) + assert.equal(layerG, drawing.getCurrentLayer()) + assert.equal(layerG.getAttribute('class'), LAYER_CLASS) + assert.equal(NEW_LAYER_NAME, drawing.getCurrentLayerName()) + assert.equal(NEW_LAYER_NAME, drawing.getLayerName(3)) - assert.equal(layerG, mockHrService.insertElement.getCall(0).args[0]); - assert.ok(mockHrService.startBatchCommand.calledOnce); - assert.ok(mockHrService.endBatchCommand.calledOnce); + assert.equal(layerG, mockHrService.insertElement.getCall(0).args[0]) + assert.ok(mockHrService.startBatchCommand.calledOnce) + assert.ok(mockHrService.endBatchCommand.calledOnce) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test mergeLayer()', function () { const mockHrService = { @@ -505,36 +505,36 @@ describe('draw.Drawing', function () { endBatchCommand () { /* empty fn */ }, moveElement () { /* empty fn */ }, removeElement () { /* empty fn */ } - }; - addOwnSpies(mockHrService); + } + addOwnSpies(mockHrService) - const drawing = new draw.Drawing(svg); - const layers = setupSVGWith3Layers(svg); - const elementCount = createSomeElementsInGroup(layers[2]) + 1; // +1 for title element - assert.equal(layers[1].childElementCount, 1); - assert.equal(layers[2].childElementCount, elementCount); - drawing.identifyLayers(); - assert.equal(drawing.getCurrentLayer(), layers[2]); + const drawing = new draw.Drawing(svg) + const layers = setupSVGWith3Layers(svg) + const elementCount = createSomeElementsInGroup(layers[2]) + 1 // +1 for title element + assert.equal(layers[1].childElementCount, 1) + assert.equal(layers[2].childElementCount, elementCount) + drawing.identifyLayers() + assert.equal(drawing.getCurrentLayer(), layers[2]) - assert.ok(drawing.mergeLayer); - assert.equal(typeof drawing.mergeLayer, typeof function () { /* empty fn */ }); + assert.ok(drawing.mergeLayer) + assert.equal(typeof drawing.mergeLayer, typeof function () { /* empty fn */ }) - drawing.mergeLayer(mockHrService); + drawing.mergeLayer(mockHrService) - assert.equal(drawing.getNumLayers(), 2); - assert.equal(svg.childElementCount, 2); - assert.equal(drawing.getCurrentLayer(), layers[1]); - assert.equal(layers[1].childElementCount, elementCount); + assert.equal(drawing.getNumLayers(), 2) + assert.equal(svg.childElementCount, 2) + assert.equal(drawing.getCurrentLayer(), layers[1]) + assert.equal(layers[1].childElementCount, elementCount) // check history record - assert.ok(mockHrService.startBatchCommand.calledOnce); - assert.ok(mockHrService.endBatchCommand.calledOnce); - assert.equal(mockHrService.startBatchCommand.getCall(0).args[0], 'Merge Layer'); - assert.equal(mockHrService.moveElement.callCount, elementCount - 1); // -1 because the title was not moved. - assert.equal(mockHrService.removeElement.callCount, 2); // remove group and title. + assert.ok(mockHrService.startBatchCommand.calledOnce) + assert.ok(mockHrService.endBatchCommand.calledOnce) + assert.equal(mockHrService.startBatchCommand.getCall(0).args[0], 'Merge Layer') + assert.equal(mockHrService.moveElement.callCount, elementCount - 1) // -1 because the title was not moved. + assert.equal(mockHrService.removeElement.callCount, 2) // remove group and title. - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test mergeLayer() when no previous layer to merge', function () { const mockHrService = { @@ -542,32 +542,32 @@ describe('draw.Drawing', function () { endBatchCommand () { /* empty fn */ }, moveElement () { /* empty fn */ }, removeElement () { /* empty fn */ } - }; - addOwnSpies(mockHrService); + } + addOwnSpies(mockHrService) - const drawing = new draw.Drawing(svg); - const layers = setupSVGWith3Layers(svg); - drawing.identifyLayers(); - drawing.setCurrentLayer(LAYER1); - assert.equal(drawing.getCurrentLayer(), layers[0]); + const drawing = new draw.Drawing(svg) + const layers = setupSVGWith3Layers(svg) + drawing.identifyLayers() + drawing.setCurrentLayer(LAYER1) + assert.equal(drawing.getCurrentLayer(), layers[0]) - drawing.mergeLayer(mockHrService); + drawing.mergeLayer(mockHrService) - assert.equal(drawing.getNumLayers(), 3); - assert.equal(svg.childElementCount, 3); - assert.equal(drawing.getCurrentLayer(), layers[0]); - assert.equal(layers[0].childElementCount, 1); - assert.equal(layers[1].childElementCount, 1); - assert.equal(layers[2].childElementCount, 1); + assert.equal(drawing.getNumLayers(), 3) + assert.equal(svg.childElementCount, 3) + assert.equal(drawing.getCurrentLayer(), layers[0]) + assert.equal(layers[0].childElementCount, 1) + assert.equal(layers[1].childElementCount, 1) + assert.equal(layers[2].childElementCount, 1) // check history record - assert.equal(mockHrService.startBatchCommand.callCount, 0); - assert.equal(mockHrService.endBatchCommand.callCount, 0); - assert.equal(mockHrService.moveElement.callCount, 0); - assert.equal(mockHrService.removeElement.callCount, 0); + assert.equal(mockHrService.startBatchCommand.callCount, 0) + assert.equal(mockHrService.endBatchCommand.callCount, 0) + assert.equal(mockHrService.moveElement.callCount, 0) + assert.equal(mockHrService.removeElement.callCount, 0) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test mergeAllLayers()', function () { const mockHrService = { @@ -575,213 +575,213 @@ describe('draw.Drawing', function () { endBatchCommand () { /* empty fn */ }, moveElement () { /* empty fn */ }, removeElement () { /* empty fn */ } - }; - addOwnSpies(mockHrService); + } + addOwnSpies(mockHrService) - const drawing = new draw.Drawing(svg); - const layers = setupSVGWith3Layers(svg); - const elementCount = createSomeElementsInGroup(layers[0]) + 1; // +1 for title element - createSomeElementsInGroup(layers[1]); - createSomeElementsInGroup(layers[2]); - assert.equal(layers[0].childElementCount, elementCount); - assert.equal(layers[1].childElementCount, elementCount); - assert.equal(layers[2].childElementCount, elementCount); - drawing.identifyLayers(); + const drawing = new draw.Drawing(svg) + const layers = setupSVGWith3Layers(svg) + const elementCount = createSomeElementsInGroup(layers[0]) + 1 // +1 for title element + createSomeElementsInGroup(layers[1]) + createSomeElementsInGroup(layers[2]) + assert.equal(layers[0].childElementCount, elementCount) + assert.equal(layers[1].childElementCount, elementCount) + assert.equal(layers[2].childElementCount, elementCount) + drawing.identifyLayers() - assert.ok(drawing.mergeAllLayers); - assert.equal(typeof drawing.mergeAllLayers, typeof function () { /* empty fn */ }); + assert.ok(drawing.mergeAllLayers) + assert.equal(typeof drawing.mergeAllLayers, typeof function () { /* empty fn */ }) - drawing.mergeAllLayers(mockHrService); + drawing.mergeAllLayers(mockHrService) - assert.equal(drawing.getNumLayers(), 1); - assert.equal(svg.childElementCount, 1); - assert.equal(drawing.getCurrentLayer(), layers[0]); - assert.equal(layers[0].childElementCount, elementCount * 3 - 2); // -2 because two titles were deleted. + assert.equal(drawing.getNumLayers(), 1) + assert.equal(svg.childElementCount, 1) + assert.equal(drawing.getCurrentLayer(), layers[0]) + assert.equal(layers[0].childElementCount, elementCount * 3 - 2) // -2 because two titles were deleted. // check history record - assert.equal(mockHrService.startBatchCommand.callCount, 3); // mergeAllLayers + 2 * mergeLayer - assert.equal(mockHrService.endBatchCommand.callCount, 3); - assert.equal(mockHrService.startBatchCommand.getCall(0).args[0], 'Merge all Layers'); - assert.equal(mockHrService.startBatchCommand.getCall(1).args[0], 'Merge Layer'); - assert.equal(mockHrService.startBatchCommand.getCall(2).args[0], 'Merge Layer'); + assert.equal(mockHrService.startBatchCommand.callCount, 3) // mergeAllLayers + 2 * mergeLayer + assert.equal(mockHrService.endBatchCommand.callCount, 3) + assert.equal(mockHrService.startBatchCommand.getCall(0).args[0], 'Merge all Layers') + assert.equal(mockHrService.startBatchCommand.getCall(1).args[0], 'Merge Layer') + assert.equal(mockHrService.startBatchCommand.getCall(2).args[0], 'Merge Layer') // moveElement count is times 3 instead of 2, because one layer's elements were moved twice. // moveElement count is minus 3 because the three titles were not moved. - assert.equal(mockHrService.moveElement.callCount, elementCount * 3 - 3); - assert.equal(mockHrService.removeElement.callCount, 2 * 2); // remove group and title twice. + assert.equal(mockHrService.moveElement.callCount, elementCount * 3 - 3) + assert.equal(mockHrService.removeElement.callCount, 2 * 2) // remove group and title twice. - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test cloneLayer()', function () { const mockHrService = { startBatchCommand () { /* empty fn */ }, endBatchCommand () { /* empty fn */ }, insertElement () { /* empty fn */ } - }; - addOwnSpies(mockHrService); + } + addOwnSpies(mockHrService) - const drawing = new draw.Drawing(svg); - const layers = setupSVGWith3Layers(svg); - const layer3 = layers[2]; - const elementCount = createSomeElementsInGroup(layer3) + 1; // +1 for title element - assert.equal(layer3.childElementCount, elementCount); - drawing.identifyLayers(); + const drawing = new draw.Drawing(svg) + const layers = setupSVGWith3Layers(svg) + const layer3 = layers[2] + const elementCount = createSomeElementsInGroup(layer3) + 1 // +1 for title element + assert.equal(layer3.childElementCount, elementCount) + drawing.identifyLayers() - assert.ok(drawing.cloneLayer); - assert.equal(typeof drawing.cloneLayer, typeof function () { /* empty fn */ }); + assert.ok(drawing.cloneLayer) + assert.equal(typeof drawing.cloneLayer, typeof function () { /* empty fn */ }) - const clone = drawing.cloneLayer('clone', mockHrService); + const clone = drawing.cloneLayer('clone', mockHrService) - assert.equal(drawing.getNumLayers(), 4); - assert.equal(svg.childElementCount, 4); - assert.equal(drawing.getCurrentLayer(), clone); - assert.equal(clone.childElementCount, elementCount); + assert.equal(drawing.getNumLayers(), 4) + assert.equal(svg.childElementCount, 4) + assert.equal(drawing.getCurrentLayer(), clone) + assert.equal(clone.childElementCount, elementCount) // check history record - assert.ok(mockHrService.startBatchCommand.calledOnce); // mergeAllLayers + 2 * mergeLayer - assert.ok(mockHrService.endBatchCommand.calledOnce); - assert.equal(mockHrService.startBatchCommand.getCall(0).args[0], 'Duplicate Layer'); - assert.equal(mockHrService.insertElement.callCount, 1); - assert.equal(mockHrService.insertElement.getCall(0).args[0], clone); + assert.ok(mockHrService.startBatchCommand.calledOnce) // mergeAllLayers + 2 * mergeLayer + assert.ok(mockHrService.endBatchCommand.calledOnce) + assert.equal(mockHrService.startBatchCommand.getCall(0).args[0], 'Duplicate Layer') + assert.equal(mockHrService.insertElement.callCount, 1) + assert.equal(mockHrService.insertElement.getCall(0).args[0], clone) // check that path is cloned properly - assert.equal(clone.childNodes.length, elementCount); - const path = clone.childNodes[1]; - assert.equal(path.id, 'svg_1'); - assert.equal(path.getAttribute('d'), PATH_ATTR.d); - assert.equal(path.getAttribute('transform'), PATH_ATTR.transform); - assert.equal(path.getAttribute('fill'), PATH_ATTR.fill); - assert.equal(path.getAttribute('stroke'), PATH_ATTR.stroke); - assert.equal(path.getAttribute('stroke-width'), PATH_ATTR['stroke-width']); + assert.equal(clone.childNodes.length, elementCount) + const path = clone.childNodes[1] + assert.equal(path.id, 'svg_1') + assert.equal(path.getAttribute('d'), PATH_ATTR.d) + assert.equal(path.getAttribute('transform'), PATH_ATTR.transform) + assert.equal(path.getAttribute('fill'), PATH_ATTR.fill) + assert.equal(path.getAttribute('stroke'), PATH_ATTR.stroke) + assert.equal(path.getAttribute('stroke-width'), PATH_ATTR['stroke-width']) // check that g is cloned properly - const g = clone.childNodes[4]; - assert.equal(g.childNodes.length, 1); - assert.equal(g.id, 'svg_4'); + const g = clone.childNodes[4] + assert.equal(g.childNodes.length, 1) + assert.equal(g.id, 'svg_4') - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test getLayerVisibility()', function () { - const drawing = new draw.Drawing(svg); - setupSVGWith3Layers(svg); - drawing.identifyLayers(); + const drawing = new draw.Drawing(svg) + setupSVGWith3Layers(svg) + drawing.identifyLayers() - assert.ok(drawing.getLayerVisibility); - assert.equal(typeof drawing.getLayerVisibility, typeof function () { /* empty fn */ }); - assert.ok(drawing.getLayerVisibility(LAYER1)); - assert.ok(drawing.getLayerVisibility(LAYER2)); - assert.ok(drawing.getLayerVisibility(LAYER3)); + assert.ok(drawing.getLayerVisibility) + assert.equal(typeof drawing.getLayerVisibility, typeof function () { /* empty fn */ }) + assert.ok(drawing.getLayerVisibility(LAYER1)) + assert.ok(drawing.getLayerVisibility(LAYER2)) + assert.ok(drawing.getLayerVisibility(LAYER3)) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test setLayerVisibility()', function () { - const drawing = new draw.Drawing(svg); - setupSVGWith3Layers(svg); - drawing.identifyLayers(); + const drawing = new draw.Drawing(svg) + setupSVGWith3Layers(svg) + drawing.identifyLayers() - assert.ok(drawing.setLayerVisibility); - assert.equal(typeof drawing.setLayerVisibility, typeof function () { /* empty fn */ }); + assert.ok(drawing.setLayerVisibility) + assert.equal(typeof drawing.setLayerVisibility, typeof function () { /* empty fn */ }) - drawing.setLayerVisibility(LAYER3, false); - drawing.setLayerVisibility(LAYER2, true); - drawing.setLayerVisibility(LAYER1, false); + drawing.setLayerVisibility(LAYER3, false) + drawing.setLayerVisibility(LAYER2, true) + drawing.setLayerVisibility(LAYER1, false) - assert.ok(!drawing.getLayerVisibility(LAYER1)); - assert.ok(drawing.getLayerVisibility(LAYER2)); - assert.ok(!drawing.getLayerVisibility(LAYER3)); + assert.ok(!drawing.getLayerVisibility(LAYER1)) + assert.ok(drawing.getLayerVisibility(LAYER2)) + assert.ok(!drawing.getLayerVisibility(LAYER3)) - drawing.setLayerVisibility(LAYER3, 'test-string'); - assert.ok(!drawing.getLayerVisibility(LAYER3)); + drawing.setLayerVisibility(LAYER3, 'test-string') + assert.ok(!drawing.getLayerVisibility(LAYER3)) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test getLayerOpacity()', function () { - const drawing = new draw.Drawing(svg); - setupSVGWith3Layers(svg); - drawing.identifyLayers(); + const drawing = new draw.Drawing(svg) + setupSVGWith3Layers(svg) + drawing.identifyLayers() - assert.ok(drawing.getLayerOpacity); - assert.equal(typeof drawing.getLayerOpacity, typeof function () { /* empty fn */ }); - assert.strictEqual(drawing.getLayerOpacity(LAYER1), 1.0); - assert.strictEqual(drawing.getLayerOpacity(LAYER2), 1.0); - assert.strictEqual(drawing.getLayerOpacity(LAYER3), 1.0); + assert.ok(drawing.getLayerOpacity) + assert.equal(typeof drawing.getLayerOpacity, typeof function () { /* empty fn */ }) + assert.strictEqual(drawing.getLayerOpacity(LAYER1), 1.0) + assert.strictEqual(drawing.getLayerOpacity(LAYER2), 1.0) + assert.strictEqual(drawing.getLayerOpacity(LAYER3), 1.0) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test setLayerOpacity()', function () { - const drawing = new draw.Drawing(svg); - setupSVGWith3Layers(svg); - drawing.identifyLayers(); + const drawing = new draw.Drawing(svg) + setupSVGWith3Layers(svg) + drawing.identifyLayers() - assert.ok(drawing.setLayerOpacity); - assert.equal(typeof drawing.setLayerOpacity, typeof function () { /* empty fn */ }); + assert.ok(drawing.setLayerOpacity) + assert.equal(typeof drawing.setLayerOpacity, typeof function () { /* empty fn */ }) - drawing.setLayerOpacity(LAYER1, 0.4); - drawing.setLayerOpacity(LAYER2, 'invalid-string'); - drawing.setLayerOpacity(LAYER3, -1.4); + drawing.setLayerOpacity(LAYER1, 0.4) + drawing.setLayerOpacity(LAYER2, 'invalid-string') + drawing.setLayerOpacity(LAYER3, -1.4) - assert.strictEqual(drawing.getLayerOpacity(LAYER1), 0.4); - assert.strictEqual(drawing.getLayerOpacity(LAYER2), 1.0); - assert.strictEqual(drawing.getLayerOpacity(LAYER3), 1.0); + assert.strictEqual(drawing.getLayerOpacity(LAYER1), 0.4) + assert.strictEqual(drawing.getLayerOpacity(LAYER2), 1.0) + assert.strictEqual(drawing.getLayerOpacity(LAYER3), 1.0) - drawing.setLayerOpacity(LAYER3, 100); - assert.strictEqual(drawing.getLayerOpacity(LAYER3), 1.0); + drawing.setLayerOpacity(LAYER3, 100) + assert.strictEqual(drawing.getLayerOpacity(LAYER3), 1.0) - cleanupSVG(svg); - }); + cleanupSVG(svg) + }) it('Test deleteCurrentLayer()', function () { - const drawing = new draw.Drawing(svg); - setupSVGWith3Layers(svg); - drawing.identifyLayers(); + const drawing = new draw.Drawing(svg) + setupSVGWith3Layers(svg) + drawing.identifyLayers() - drawing.setCurrentLayer(LAYER2); + drawing.setCurrentLayer(LAYER2) - const curLayer = drawing.getCurrentLayer(); - assert.equal(curLayer, drawing.all_layers[1].getGroup()); - const deletedLayer = drawing.deleteCurrentLayer(); + const curLayer = drawing.getCurrentLayer() + assert.equal(curLayer, drawing.all_layers[1].getGroup()) + const deletedLayer = drawing.deleteCurrentLayer() - assert.equal(curLayer, deletedLayer); - assert.equal(drawing.getNumLayers(), 2); - assert.equal(LAYER1, drawing.all_layers[0].getName()); - assert.equal(LAYER3, drawing.all_layers[1].getName()); - assert.equal(drawing.getCurrentLayer(), drawing.all_layers[1].getGroup()); - }); + assert.equal(curLayer, deletedLayer) + assert.equal(drawing.getNumLayers(), 2) + assert.equal(LAYER1, drawing.all_layers[0].getName()) + assert.equal(LAYER3, drawing.all_layers[1].getName()) + assert.equal(drawing.getCurrentLayer(), drawing.all_layers[1].getGroup()) + }) it('Test svgedit.draw.randomizeIds()', function () { // Confirm in LET_DOCUMENT_DECIDE mode that the document decides // if there is a nonce. - let drawing = new draw.Drawing(svgN.cloneNode(true)); - assert.ok(drawing.getNonce()); + let drawing = new draw.Drawing(svgN.cloneNode(true)) + assert.ok(drawing.getNonce()) - drawing = new draw.Drawing(svg.cloneNode(true)); - assert.ok(!drawing.getNonce()); + drawing = new draw.Drawing(svg.cloneNode(true)) + assert.ok(!drawing.getNonce()) // Confirm that a nonce is set once we're in ALWAYS_RANDOMIZE mode. - draw.randomizeIds(true, drawing); - assert.ok(drawing.getNonce()); + draw.randomizeIds(true, drawing) + assert.ok(drawing.getNonce()) // Confirm new drawings in ALWAYS_RANDOMIZE mode have a nonce. - drawing = new draw.Drawing(svg.cloneNode(true)); - assert.ok(drawing.getNonce()); + drawing = new draw.Drawing(svg.cloneNode(true)) + assert.ok(drawing.getNonce()) - drawing.clearNonce(); - assert.ok(!drawing.getNonce()); + drawing.clearNonce() + assert.ok(!drawing.getNonce()) // Confirm new drawings in NEVER_RANDOMIZE mode do not have a nonce // but that their se:nonce attribute is left alone. - draw.randomizeIds(false, drawing); - assert.ok(!drawing.getNonce()); - assert.ok(drawing.getSvgElem().getAttributeNS(NS.SE, 'nonce')); + draw.randomizeIds(false, drawing) + assert.ok(!drawing.getNonce()) + assert.ok(drawing.getSvgElem().getAttributeNS(NS.SE, 'nonce')) - drawing = new draw.Drawing(svg.cloneNode(true)); - assert.ok(!drawing.getNonce()); + drawing = new draw.Drawing(svg.cloneNode(true)) + assert.ok(!drawing.getNonce()) - drawing = new draw.Drawing(svgN.cloneNode(true)); - assert.ok(!drawing.getNonce()); - }); -}); + drawing = new draw.Drawing(svgN.cloneNode(true)) + assert.ok(!drawing.getNonce()) + }) +}) diff --git a/cypress/integration/unit/history.js b/cypress/integration/unit/history.js index ca11d8be..0c2f943d 100644 --- a/cypress/integration/unit/history.js +++ b/cypress/integration/unit/history.js @@ -1,31 +1,34 @@ -import { NS } from '../../../instrumented/svgcanvas/namespaces.js'; -import * as utilities from '../../../instrumented/svgcanvas/utilities.js'; -import * as history from '../../../instrumented/svgcanvas/history.js'; +import { NS } from '../../../instrumented/svgcanvas/namespaces.js' +import * as utilities from '../../../instrumented/svgcanvas/utilities.js' +import * as history from '../../../instrumented/svgcanvas/history.js' describe('history', function () { // TODO(codedread): Write tests for handling history events. utilities.mock({ - getHref () { return '#foo'; }, + getHref () { return '#foo' }, setHref () { /* empty fn */ }, - getRotationAngle () { return 0; } - }); + getRotationAngle () { return 0 } + }) // const svg = document.createElementNS(NS.SVG, 'svg'); - let undoMgr = null; + let undoMgr = null class MockCommand extends history.Command { constructor (optText) { - super(); - this.text = optText; + super() + this.text = optText } + apply (handler) { - super.apply(handler, () => { /* empty fn */ }); + super.apply(handler, () => { /* empty fn */ }) } + unapply (handler) { - super.unapply(handler, () => { /* empty fn */ }); + super.unapply(handler, () => { /* empty fn */ }) } - elements () { return []; } + + elements () { return [] } } /* @@ -39,479 +42,479 @@ describe('history', function () { * @returns {void} */ beforeEach(function () { - undoMgr = new history.UndoManager(); + undoMgr = new history.UndoManager() - document.body.textContent = ''; - this.divparent = document.createElement('div'); - this.divparent.id = 'divparent'; - this.divparent.style.visibility = 'hidden'; + document.body.textContent = '' + this.divparent = document.createElement('div') + this.divparent.id = 'divparent' + this.divparent.style.visibility = 'hidden' for (let i = 1; i <= 5; i++) { - const div = document.createElement('div'); - const id = `div${i}`; - div.id = id; - this[id] = div; + const div = document.createElement('div') + const id = `div${i}` + div.id = id + this[id] = div } - this.divparent.append(this.div1, this.div2, this.div3); + this.divparent.append(this.div1, this.div2, this.div3) - this.div4.style.visibility = 'hidden'; - this.div4.append(this.div5); + this.div4.style.visibility = 'hidden' + this.div4.append(this.div5) - document.body.append(this.divparent, this.div); - }); + document.body.append(this.divparent, this.div) + }) /** * Tear down tests, destroying undo manager. * @returns {void} */ afterEach(() => { - undoMgr = null; - }); + undoMgr = null + }) it('Test svgedit.history package', function () { - assert.ok(history); - assert.ok(history.MoveElementCommand); - assert.ok(history.InsertElementCommand); - assert.ok(history.ChangeElementCommand); - assert.ok(history.RemoveElementCommand); - assert.ok(history.BatchCommand); - assert.ok(history.UndoManager); - assert.equal(typeof history.MoveElementCommand, typeof function () { /* empty fn */ }); - assert.equal(typeof history.InsertElementCommand, typeof function () { /* empty fn */ }); - assert.equal(typeof history.ChangeElementCommand, typeof function () { /* empty fn */ }); - assert.equal(typeof history.RemoveElementCommand, typeof function () { /* empty fn */ }); - assert.equal(typeof history.BatchCommand, typeof function () { /* empty fn */ }); - assert.equal(typeof history.UndoManager, typeof function () { /* empty fn */ }); - }); + assert.ok(history) + assert.ok(history.MoveElementCommand) + assert.ok(history.InsertElementCommand) + assert.ok(history.ChangeElementCommand) + assert.ok(history.RemoveElementCommand) + assert.ok(history.BatchCommand) + assert.ok(history.UndoManager) + assert.equal(typeof history.MoveElementCommand, typeof function () { /* empty fn */ }) + assert.equal(typeof history.InsertElementCommand, typeof function () { /* empty fn */ }) + assert.equal(typeof history.ChangeElementCommand, typeof function () { /* empty fn */ }) + assert.equal(typeof history.RemoveElementCommand, typeof function () { /* empty fn */ }) + assert.equal(typeof history.BatchCommand, typeof function () { /* empty fn */ }) + assert.equal(typeof history.UndoManager, typeof function () { /* empty fn */ }) + }) it('Test UndoManager methods', function () { - assert.ok(undoMgr); - assert.ok(undoMgr.addCommandToHistory); - assert.ok(undoMgr.getUndoStackSize); - assert.ok(undoMgr.getRedoStackSize); - assert.ok(undoMgr.resetUndoStack); - assert.ok(undoMgr.getNextUndoCommandText); - assert.ok(undoMgr.getNextRedoCommandText); + assert.ok(undoMgr) + assert.ok(undoMgr.addCommandToHistory) + assert.ok(undoMgr.getUndoStackSize) + assert.ok(undoMgr.getRedoStackSize) + assert.ok(undoMgr.resetUndoStack) + assert.ok(undoMgr.getNextUndoCommandText) + assert.ok(undoMgr.getNextRedoCommandText) - assert.equal(typeof undoMgr, typeof {}); - assert.equal(typeof undoMgr.addCommandToHistory, typeof function () { /* empty fn */ }); - assert.equal(typeof undoMgr.getUndoStackSize, typeof function () { /* empty fn */ }); - assert.equal(typeof undoMgr.getRedoStackSize, typeof function () { /* empty fn */ }); - assert.equal(typeof undoMgr.resetUndoStack, typeof function () { /* empty fn */ }); - assert.equal(typeof undoMgr.getNextUndoCommandText, typeof function () { /* empty fn */ }); - assert.equal(typeof undoMgr.getNextRedoCommandText, typeof function () { /* empty fn */ }); - }); + assert.equal(typeof undoMgr, typeof {}) + assert.equal(typeof undoMgr.addCommandToHistory, typeof function () { /* empty fn */ }) + assert.equal(typeof undoMgr.getUndoStackSize, typeof function () { /* empty fn */ }) + assert.equal(typeof undoMgr.getRedoStackSize, typeof function () { /* empty fn */ }) + assert.equal(typeof undoMgr.resetUndoStack, typeof function () { /* empty fn */ }) + assert.equal(typeof undoMgr.getNextUndoCommandText, typeof function () { /* empty fn */ }) + assert.equal(typeof undoMgr.getNextRedoCommandText, typeof function () { /* empty fn */ }) + }) it('Test UndoManager.addCommandToHistory() function', function () { - assert.equal(undoMgr.getUndoStackSize(), 0); - undoMgr.addCommandToHistory(new MockCommand()); - assert.equal(undoMgr.getUndoStackSize(), 1); - undoMgr.addCommandToHistory(new MockCommand()); - assert.equal(undoMgr.getUndoStackSize(), 2); - }); + assert.equal(undoMgr.getUndoStackSize(), 0) + undoMgr.addCommandToHistory(new MockCommand()) + assert.equal(undoMgr.getUndoStackSize(), 1) + undoMgr.addCommandToHistory(new MockCommand()) + assert.equal(undoMgr.getUndoStackSize(), 2) + }) it('Test UndoManager.getUndoStackSize() and getRedoStackSize() functions', function () { - undoMgr.addCommandToHistory(new MockCommand()); - undoMgr.addCommandToHistory(new MockCommand()); - undoMgr.addCommandToHistory(new MockCommand()); + undoMgr.addCommandToHistory(new MockCommand()) + undoMgr.addCommandToHistory(new MockCommand()) + undoMgr.addCommandToHistory(new MockCommand()) - assert.equal(undoMgr.getUndoStackSize(), 3); - assert.equal(undoMgr.getRedoStackSize(), 0); + assert.equal(undoMgr.getUndoStackSize(), 3) + assert.equal(undoMgr.getRedoStackSize(), 0) - undoMgr.undo(); - assert.equal(undoMgr.getUndoStackSize(), 2); - assert.equal(undoMgr.getRedoStackSize(), 1); + undoMgr.undo() + assert.equal(undoMgr.getUndoStackSize(), 2) + assert.equal(undoMgr.getRedoStackSize(), 1) - undoMgr.undo(); - assert.equal(undoMgr.getUndoStackSize(), 1); - assert.equal(undoMgr.getRedoStackSize(), 2); + undoMgr.undo() + assert.equal(undoMgr.getUndoStackSize(), 1) + assert.equal(undoMgr.getRedoStackSize(), 2) - undoMgr.undo(); - assert.equal(undoMgr.getUndoStackSize(), 0); - assert.equal(undoMgr.getRedoStackSize(), 3); + undoMgr.undo() + assert.equal(undoMgr.getUndoStackSize(), 0) + assert.equal(undoMgr.getRedoStackSize(), 3) - undoMgr.undo(); - assert.equal(undoMgr.getUndoStackSize(), 0); - assert.equal(undoMgr.getRedoStackSize(), 3); + undoMgr.undo() + assert.equal(undoMgr.getUndoStackSize(), 0) + assert.equal(undoMgr.getRedoStackSize(), 3) - undoMgr.redo(); - assert.equal(undoMgr.getUndoStackSize(), 1); - assert.equal(undoMgr.getRedoStackSize(), 2); + undoMgr.redo() + assert.equal(undoMgr.getUndoStackSize(), 1) + assert.equal(undoMgr.getRedoStackSize(), 2) - undoMgr.redo(); - assert.equal(undoMgr.getUndoStackSize(), 2); - assert.equal(undoMgr.getRedoStackSize(), 1); + undoMgr.redo() + assert.equal(undoMgr.getUndoStackSize(), 2) + assert.equal(undoMgr.getRedoStackSize(), 1) - undoMgr.redo(); - assert.equal(undoMgr.getUndoStackSize(), 3); - assert.equal(undoMgr.getRedoStackSize(), 0); + undoMgr.redo() + assert.equal(undoMgr.getUndoStackSize(), 3) + assert.equal(undoMgr.getRedoStackSize(), 0) - undoMgr.redo(); - assert.equal(undoMgr.getUndoStackSize(), 3); - assert.equal(undoMgr.getRedoStackSize(), 0); - }); + undoMgr.redo() + assert.equal(undoMgr.getUndoStackSize(), 3) + assert.equal(undoMgr.getRedoStackSize(), 0) + }) it('Test UndoManager.resetUndoStackSize() function', function () { - undoMgr.addCommandToHistory(new MockCommand()); - undoMgr.addCommandToHistory(new MockCommand()); - undoMgr.addCommandToHistory(new MockCommand()); - undoMgr.undo(); + undoMgr.addCommandToHistory(new MockCommand()) + undoMgr.addCommandToHistory(new MockCommand()) + undoMgr.addCommandToHistory(new MockCommand()) + undoMgr.undo() - assert.equal(undoMgr.getUndoStackSize(), 2); - assert.equal(undoMgr.getRedoStackSize(), 1); + assert.equal(undoMgr.getUndoStackSize(), 2) + assert.equal(undoMgr.getRedoStackSize(), 1) - undoMgr.resetUndoStack(); + undoMgr.resetUndoStack() - assert.equal(undoMgr.getUndoStackSize(), 0); - assert.equal(undoMgr.getRedoStackSize(), 0); - }); + assert.equal(undoMgr.getUndoStackSize(), 0) + assert.equal(undoMgr.getRedoStackSize(), 0) + }) it('Test UndoManager.getNextUndoCommandText() function', function () { - assert.equal(undoMgr.getNextUndoCommandText(), ''); + assert.equal(undoMgr.getNextUndoCommandText(), '') - undoMgr.addCommandToHistory(new MockCommand('First')); - undoMgr.addCommandToHistory(new MockCommand('Second')); - undoMgr.addCommandToHistory(new MockCommand('Third')); + undoMgr.addCommandToHistory(new MockCommand('First')) + undoMgr.addCommandToHistory(new MockCommand('Second')) + undoMgr.addCommandToHistory(new MockCommand('Third')) - assert.equal(undoMgr.getNextUndoCommandText(), 'Third'); + assert.equal(undoMgr.getNextUndoCommandText(), 'Third') - undoMgr.undo(); - assert.equal(undoMgr.getNextUndoCommandText(), 'Second'); + undoMgr.undo() + assert.equal(undoMgr.getNextUndoCommandText(), 'Second') - undoMgr.undo(); - assert.equal(undoMgr.getNextUndoCommandText(), 'First'); + undoMgr.undo() + assert.equal(undoMgr.getNextUndoCommandText(), 'First') - undoMgr.undo(); - assert.equal(undoMgr.getNextUndoCommandText(), ''); + undoMgr.undo() + assert.equal(undoMgr.getNextUndoCommandText(), '') - undoMgr.redo(); - assert.equal(undoMgr.getNextUndoCommandText(), 'First'); + undoMgr.redo() + assert.equal(undoMgr.getNextUndoCommandText(), 'First') - undoMgr.redo(); - assert.equal(undoMgr.getNextUndoCommandText(), 'Second'); + undoMgr.redo() + assert.equal(undoMgr.getNextUndoCommandText(), 'Second') - undoMgr.redo(); - assert.equal(undoMgr.getNextUndoCommandText(), 'Third'); + undoMgr.redo() + assert.equal(undoMgr.getNextUndoCommandText(), 'Third') - undoMgr.redo(); - assert.equal(undoMgr.getNextUndoCommandText(), 'Third'); - }); + undoMgr.redo() + assert.equal(undoMgr.getNextUndoCommandText(), 'Third') + }) it('Test UndoManager.getNextRedoCommandText() function', function () { - assert.equal(undoMgr.getNextRedoCommandText(), ''); + assert.equal(undoMgr.getNextRedoCommandText(), '') - undoMgr.addCommandToHistory(new MockCommand('First')); - undoMgr.addCommandToHistory(new MockCommand('Second')); - undoMgr.addCommandToHistory(new MockCommand('Third')); + undoMgr.addCommandToHistory(new MockCommand('First')) + undoMgr.addCommandToHistory(new MockCommand('Second')) + undoMgr.addCommandToHistory(new MockCommand('Third')) - assert.equal(undoMgr.getNextRedoCommandText(), ''); + assert.equal(undoMgr.getNextRedoCommandText(), '') - undoMgr.undo(); - assert.equal(undoMgr.getNextRedoCommandText(), 'Third'); + undoMgr.undo() + assert.equal(undoMgr.getNextRedoCommandText(), 'Third') - undoMgr.undo(); - assert.equal(undoMgr.getNextRedoCommandText(), 'Second'); + undoMgr.undo() + assert.equal(undoMgr.getNextRedoCommandText(), 'Second') - undoMgr.undo(); - assert.equal(undoMgr.getNextRedoCommandText(), 'First'); + undoMgr.undo() + assert.equal(undoMgr.getNextRedoCommandText(), 'First') - undoMgr.redo(); - assert.equal(undoMgr.getNextRedoCommandText(), 'Second'); + undoMgr.redo() + assert.equal(undoMgr.getNextRedoCommandText(), 'Second') - undoMgr.redo(); - assert.equal(undoMgr.getNextRedoCommandText(), 'Third'); + undoMgr.redo() + assert.equal(undoMgr.getNextRedoCommandText(), 'Third') - undoMgr.redo(); - assert.equal(undoMgr.getNextRedoCommandText(), ''); - }); + undoMgr.redo() + assert.equal(undoMgr.getNextRedoCommandText(), '') + }) it('Test UndoManager.undo() and redo() functions', function () { - let lastCalled = null; - const cmd1 = new MockCommand(); - const cmd2 = new MockCommand(); - const cmd3 = new MockCommand(); - cmd1.apply = function () { lastCalled = 'cmd1.apply'; }; - cmd2.apply = function () { lastCalled = 'cmd2.apply'; }; - cmd3.apply = function () { lastCalled = 'cmd3.apply'; }; - cmd1.unapply = function () { lastCalled = 'cmd1.unapply'; }; - cmd2.unapply = function () { lastCalled = 'cmd2.unapply'; }; - cmd3.unapply = function () { lastCalled = 'cmd3.unapply'; }; + let lastCalled = null + const cmd1 = new MockCommand() + const cmd2 = new MockCommand() + const cmd3 = new MockCommand() + cmd1.apply = function () { lastCalled = 'cmd1.apply' } + cmd2.apply = function () { lastCalled = 'cmd2.apply' } + cmd3.apply = function () { lastCalled = 'cmd3.apply' } + cmd1.unapply = function () { lastCalled = 'cmd1.unapply' } + cmd2.unapply = function () { lastCalled = 'cmd2.unapply' } + cmd3.unapply = function () { lastCalled = 'cmd3.unapply' } - undoMgr.addCommandToHistory(cmd1); - undoMgr.addCommandToHistory(cmd2); - undoMgr.addCommandToHistory(cmd3); + undoMgr.addCommandToHistory(cmd1) + undoMgr.addCommandToHistory(cmd2) + undoMgr.addCommandToHistory(cmd3) - assert.ok(!lastCalled); + assert.ok(!lastCalled) - undoMgr.undo(); - assert.equal(lastCalled, 'cmd3.unapply'); + undoMgr.undo() + assert.equal(lastCalled, 'cmd3.unapply') - undoMgr.redo(); - assert.equal(lastCalled, 'cmd3.apply'); + undoMgr.redo() + assert.equal(lastCalled, 'cmd3.apply') - undoMgr.undo(); - undoMgr.undo(); - assert.equal(lastCalled, 'cmd2.unapply'); + undoMgr.undo() + undoMgr.undo() + assert.equal(lastCalled, 'cmd2.unapply') - undoMgr.undo(); - assert.equal(lastCalled, 'cmd1.unapply'); - lastCalled = null; + undoMgr.undo() + assert.equal(lastCalled, 'cmd1.unapply') + lastCalled = null - undoMgr.undo(); - assert.ok(!lastCalled); + undoMgr.undo() + assert.ok(!lastCalled) - undoMgr.redo(); - assert.equal(lastCalled, 'cmd1.apply'); + undoMgr.redo() + assert.equal(lastCalled, 'cmd1.apply') - undoMgr.redo(); - assert.equal(lastCalled, 'cmd2.apply'); + undoMgr.redo() + assert.equal(lastCalled, 'cmd2.apply') - undoMgr.redo(); - assert.equal(lastCalled, 'cmd3.apply'); - lastCalled = null; + undoMgr.redo() + assert.equal(lastCalled, 'cmd3.apply') + lastCalled = null - undoMgr.redo(); - assert.ok(!lastCalled); - }); + undoMgr.redo() + assert.ok(!lastCalled) + }) it('Test MoveElementCommand', function () { - let move = new history.MoveElementCommand(this.div3, this.div1, this.divparent); - assert.ok(move.unapply); - assert.ok(move.apply); - assert.equal(typeof move.unapply, typeof function () { /* empty fn */ }); - assert.equal(typeof move.apply, typeof function () { /* empty fn */ }); + let move = new history.MoveElementCommand(this.div3, this.div1, this.divparent) + assert.ok(move.unapply) + assert.ok(move.apply) + assert.equal(typeof move.unapply, typeof function () { /* empty fn */ }) + assert.equal(typeof move.apply, typeof function () { /* empty fn */ }) - move.unapply(); - assert.equal(this.divparent.firstElementChild, this.div3); - assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div1); - assert.equal(this.divparent.lastElementChild, this.div2); + move.unapply() + assert.equal(this.divparent.firstElementChild, this.div3) + assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div1) + assert.equal(this.divparent.lastElementChild, this.div2) - move.apply(); - assert.equal(this.divparent.firstElementChild, this.div1); - assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div2); - assert.equal(this.divparent.lastElementChild, this.div3); + move.apply() + assert.equal(this.divparent.firstElementChild, this.div1) + assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div2) + assert.equal(this.divparent.lastElementChild, this.div3) - move = new history.MoveElementCommand(this.div1, null, this.divparent); + move = new history.MoveElementCommand(this.div1, null, this.divparent) - move.unapply(); - assert.equal(this.divparent.firstElementChild, this.div2); - assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div3); - assert.equal(this.divparent.lastElementChild, this.div1); + move.unapply() + assert.equal(this.divparent.firstElementChild, this.div2) + assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div3) + assert.equal(this.divparent.lastElementChild, this.div1) - move.apply(); - assert.equal(this.divparent.firstElementChild, this.div1); - assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div2); - assert.equal(this.divparent.lastElementChild, this.div3); + move.apply() + assert.equal(this.divparent.firstElementChild, this.div1) + assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div2) + assert.equal(this.divparent.lastElementChild, this.div3) - move = new history.MoveElementCommand(this.div2, this.div5, this.div4); + move = new history.MoveElementCommand(this.div2, this.div5, this.div4) - move.unapply(); - assert.equal(this.divparent.firstElementChild, this.div1); - assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div3); - assert.equal(this.divparent.lastElementChild, this.div3); - assert.equal(this.div4.firstElementChild, this.div2); - assert.equal(this.div4.firstElementChild.nextElementSibling, this.div5); + move.unapply() + assert.equal(this.divparent.firstElementChild, this.div1) + assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div3) + assert.equal(this.divparent.lastElementChild, this.div3) + assert.equal(this.div4.firstElementChild, this.div2) + assert.equal(this.div4.firstElementChild.nextElementSibling, this.div5) - move.apply(); - assert.equal(this.divparent.firstElementChild, this.div1); - assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div2); - assert.equal(this.divparent.lastElementChild, this.div3); - assert.equal(this.div4.firstElementChild, this.div5); - assert.equal(this.div4.lastElementChild, this.div5); - }); + move.apply() + assert.equal(this.divparent.firstElementChild, this.div1) + assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div2) + assert.equal(this.divparent.lastElementChild, this.div3) + assert.equal(this.div4.firstElementChild, this.div5) + assert.equal(this.div4.lastElementChild, this.div5) + }) it('Test InsertElementCommand', function () { - let insert = new history.InsertElementCommand(this.div3); - assert.ok(insert.unapply); - assert.ok(insert.apply); - assert.equal(typeof insert.unapply, typeof function () { /* empty fn */ }); - assert.equal(typeof insert.apply, typeof function () { /* empty fn */ }); + let insert = new history.InsertElementCommand(this.div3) + assert.ok(insert.unapply) + assert.ok(insert.apply) + assert.equal(typeof insert.unapply, typeof function () { /* empty fn */ }) + assert.equal(typeof insert.apply, typeof function () { /* empty fn */ }) - insert.unapply(); - assert.equal(this.divparent.childElementCount, 2); - assert.equal(this.divparent.firstElementChild, this.div1); - assert.equal(this.div1.nextElementSibling, this.div2); - assert.equal(this.divparent.lastElementChild, this.div2); + insert.unapply() + assert.equal(this.divparent.childElementCount, 2) + assert.equal(this.divparent.firstElementChild, this.div1) + assert.equal(this.div1.nextElementSibling, this.div2) + assert.equal(this.divparent.lastElementChild, this.div2) - insert.apply(); - assert.equal(this.divparent.childElementCount, 3); - assert.equal(this.divparent.firstElementChild, this.div1); - assert.equal(this.div1.nextElementSibling, this.div2); - assert.equal(this.div2.nextElementSibling, this.div3); + insert.apply() + assert.equal(this.divparent.childElementCount, 3) + assert.equal(this.divparent.firstElementChild, this.div1) + assert.equal(this.div1.nextElementSibling, this.div2) + assert.equal(this.div2.nextElementSibling, this.div3) - insert = new history.InsertElementCommand(this.div2); + insert = new history.InsertElementCommand(this.div2) - insert.unapply(); - assert.equal(this.divparent.childElementCount, 2); - assert.equal(this.divparent.firstElementChild, this.div1); - assert.equal(this.div1.nextElementSibling, this.div3); - assert.equal(this.divparent.lastElementChild, this.div3); + insert.unapply() + assert.equal(this.divparent.childElementCount, 2) + assert.equal(this.divparent.firstElementChild, this.div1) + assert.equal(this.div1.nextElementSibling, this.div3) + assert.equal(this.divparent.lastElementChild, this.div3) - insert.apply(); - assert.equal(this.divparent.childElementCount, 3); - assert.equal(this.divparent.firstElementChild, this.div1); - assert.equal(this.div1.nextElementSibling, this.div2); - assert.equal(this.div2.nextElementSibling, this.div3); - }); + insert.apply() + assert.equal(this.divparent.childElementCount, 3) + assert.equal(this.divparent.firstElementChild, this.div1) + assert.equal(this.div1.nextElementSibling, this.div2) + assert.equal(this.div2.nextElementSibling, this.div3) + }) it('Test RemoveElementCommand', function () { - const div6 = document.createElement('div'); - div6.id = 'div6'; + const div6 = document.createElement('div') + div6.id = 'div6' - let remove = new history.RemoveElementCommand(div6, null, this.divparent); - assert.ok(remove.unapply); - assert.ok(remove.apply); - assert.equal(typeof remove.unapply, typeof function () { /* empty fn */ }); - assert.equal(typeof remove.apply, typeof function () { /* empty fn */ }); + let remove = new history.RemoveElementCommand(div6, null, this.divparent) + assert.ok(remove.unapply) + assert.ok(remove.apply) + assert.equal(typeof remove.unapply, typeof function () { /* empty fn */ }) + assert.equal(typeof remove.apply, typeof function () { /* empty fn */ }) - remove.unapply(); - assert.equal(this.divparent.childElementCount, 4); - assert.equal(this.divparent.firstElementChild, this.div1); - assert.equal(this.div1.nextElementSibling, this.div2); - assert.equal(this.div2.nextElementSibling, this.div3); - assert.equal(this.div3.nextElementSibling, div6); + remove.unapply() + assert.equal(this.divparent.childElementCount, 4) + assert.equal(this.divparent.firstElementChild, this.div1) + assert.equal(this.div1.nextElementSibling, this.div2) + assert.equal(this.div2.nextElementSibling, this.div3) + assert.equal(this.div3.nextElementSibling, div6) - remove.apply(); - assert.equal(this.divparent.childElementCount, 3); - assert.equal(this.divparent.firstElementChild, this.div1); - assert.equal(this.div1.nextElementSibling, this.div2); - assert.equal(this.div2.nextElementSibling, this.div3); + remove.apply() + assert.equal(this.divparent.childElementCount, 3) + assert.equal(this.divparent.firstElementChild, this.div1) + assert.equal(this.div1.nextElementSibling, this.div2) + assert.equal(this.div2.nextElementSibling, this.div3) - remove = new history.RemoveElementCommand(div6, this.div2, this.divparent); + remove = new history.RemoveElementCommand(div6, this.div2, this.divparent) - remove.unapply(); - assert.equal(this.divparent.childElementCount, 4); - assert.equal(this.divparent.firstElementChild, this.div1); - assert.equal(this.div1.nextElementSibling, div6); - assert.equal(div6.nextElementSibling, this.div2); - assert.equal(this.div2.nextElementSibling, this.div3); + remove.unapply() + assert.equal(this.divparent.childElementCount, 4) + assert.equal(this.divparent.firstElementChild, this.div1) + assert.equal(this.div1.nextElementSibling, div6) + assert.equal(div6.nextElementSibling, this.div2) + assert.equal(this.div2.nextElementSibling, this.div3) - remove.apply(); - assert.equal(this.divparent.childElementCount, 3); - assert.equal(this.divparent.firstElementChild, this.div1); - assert.equal(this.div1.nextElementSibling, this.div2); - assert.equal(this.div2.nextElementSibling, this.div3); - }); + remove.apply() + assert.equal(this.divparent.childElementCount, 3) + assert.equal(this.divparent.firstElementChild, this.div1) + assert.equal(this.div1.nextElementSibling, this.div2) + assert.equal(this.div2.nextElementSibling, this.div3) + }) it('Test ChangeElementCommand', function () { - this.div1.setAttribute('title', 'new title'); + this.div1.setAttribute('title', 'new title') let change = new history.ChangeElementCommand(this.div1, - { title: 'old title', class: 'foo' }); - assert.ok(change.unapply); - assert.ok(change.apply); - assert.equal(typeof change.unapply, typeof function () { /* empty fn */ }); - assert.equal(typeof change.apply, typeof function () { /* empty fn */ }); + { title: 'old title', class: 'foo' }) + assert.ok(change.unapply) + assert.ok(change.apply) + assert.equal(typeof change.unapply, typeof function () { /* empty fn */ }) + assert.equal(typeof change.apply, typeof function () { /* empty fn */ }) - change.unapply(); - assert.equal(this.div1.getAttribute('title'), 'old title'); - assert.equal(this.div1.getAttribute('class'), 'foo'); + change.unapply() + assert.equal(this.div1.getAttribute('title'), 'old title') + assert.equal(this.div1.getAttribute('class'), 'foo') - change.apply(); - assert.equal(this.div1.getAttribute('title'), 'new title'); - assert.ok(!this.div1.getAttribute('class')); + change.apply() + assert.equal(this.div1.getAttribute('title'), 'new title') + assert.ok(!this.div1.getAttribute('class')) - this.div1.textContent = 'inner text'; + this.div1.textContent = 'inner text' change = new history.ChangeElementCommand(this.div1, - { '#text': null }); + { '#text': null }) - change.unapply(); - assert.ok(!this.div1.textContent); + change.unapply() + assert.ok(!this.div1.textContent) - change.apply(); - assert.equal(this.div1.textContent, 'inner text'); + change.apply() + assert.equal(this.div1.textContent, 'inner text') - this.div1.textContent = ''; + this.div1.textContent = '' change = new history.ChangeElementCommand(this.div1, - { '#text': 'old text' }); + { '#text': 'old text' }) - change.unapply(); - assert.equal(this.div1.textContent, 'old text'); + change.unapply() + assert.equal(this.div1.textContent, 'old text') - change.apply(); - assert.ok(!this.div1.textContent); + change.apply() + assert.ok(!this.div1.textContent) // TODO(codedread): Refactor this #href stuff in history.js and svgcanvas.js - const rect = document.createElementNS(NS.SVG, 'rect'); - let justCalled = null; - let gethrefvalue = null; - let sethrefvalue = null; + const rect = document.createElementNS(NS.SVG, 'rect') + let justCalled = null + let gethrefvalue = null + let sethrefvalue = null utilities.mock({ getHref (elem) { - assert.equal(elem, rect); - justCalled = 'getHref'; - return gethrefvalue; + assert.equal(elem, rect) + justCalled = 'getHref' + return gethrefvalue }, setHref (elem, val) { - assert.equal(elem, rect); - assert.equal(val, sethrefvalue); - justCalled = 'setHref'; + assert.equal(elem, rect) + assert.equal(val, sethrefvalue) + justCalled = 'setHref' }, - getRotationAngle () { return 0; } - }); + getRotationAngle () { return 0 } + }) - gethrefvalue = '#newhref'; + gethrefvalue = '#newhref' change = new history.ChangeElementCommand(rect, - { '#href': '#oldhref' }); - assert.equal(justCalled, 'getHref'); + { '#href': '#oldhref' }) + assert.equal(justCalled, 'getHref') - justCalled = null; - sethrefvalue = '#oldhref'; - change.unapply(); - assert.equal(justCalled, 'setHref'); + justCalled = null + sethrefvalue = '#oldhref' + change.unapply() + assert.equal(justCalled, 'setHref') - justCalled = null; - sethrefvalue = '#newhref'; - change.apply(); - assert.equal(justCalled, 'setHref'); + justCalled = null + sethrefvalue = '#newhref' + change.apply() + assert.equal(justCalled, 'setHref') - const line = document.createElementNS(NS.SVG, 'line'); - line.setAttribute('class', 'newClass'); - change = new history.ChangeElementCommand(line, { class: 'oldClass' }); + const line = document.createElementNS(NS.SVG, 'line') + line.setAttribute('class', 'newClass') + change = new history.ChangeElementCommand(line, { class: 'oldClass' }) - assert.ok(change.unapply); - assert.ok(change.apply); - assert.equal(typeof change.unapply, typeof function () { /* empty fn */ }); - assert.equal(typeof change.apply, typeof function () { /* empty fn */ }); + assert.ok(change.unapply) + assert.ok(change.apply) + assert.equal(typeof change.unapply, typeof function () { /* empty fn */ }) + assert.equal(typeof change.apply, typeof function () { /* empty fn */ }) - change.unapply(); - assert.equal(line.getAttribute('class'), 'oldClass'); + change.unapply() + assert.equal(line.getAttribute('class'), 'oldClass') - change.apply(); - assert.equal(line.getAttribute('class'), 'newClass'); - }); + change.apply() + assert.equal(line.getAttribute('class'), 'newClass') + }) it('Test BatchCommand', function () { - let concatResult = ''; - MockCommand.prototype.apply = function () { concatResult += this.text; }; + let concatResult = '' + MockCommand.prototype.apply = function () { concatResult += this.text } - const batch = new history.BatchCommand(); - assert.ok(batch.unapply); - assert.ok(batch.apply); - assert.ok(batch.addSubCommand); - assert.ok(batch.isEmpty); - assert.equal(typeof batch.unapply, 'function'); - assert.equal(typeof batch.apply, 'function'); - assert.equal(typeof batch.addSubCommand, 'function'); - assert.equal(typeof batch.isEmpty, 'function'); + const batch = new history.BatchCommand() + assert.ok(batch.unapply) + assert.ok(batch.apply) + assert.ok(batch.addSubCommand) + assert.ok(batch.isEmpty) + assert.equal(typeof batch.unapply, 'function') + assert.equal(typeof batch.apply, 'function') + assert.equal(typeof batch.addSubCommand, 'function') + assert.equal(typeof batch.isEmpty, 'function') - assert.ok(batch.isEmpty()); + assert.ok(batch.isEmpty()) - batch.addSubCommand(new MockCommand('a')); - assert.ok(!batch.isEmpty()); - batch.addSubCommand(new MockCommand('b')); - batch.addSubCommand(new MockCommand('c')); + batch.addSubCommand(new MockCommand('a')) + assert.ok(!batch.isEmpty()) + batch.addSubCommand(new MockCommand('b')) + batch.addSubCommand(new MockCommand('c')) - assert.ok(!concatResult); - batch.apply(); - assert.equal(concatResult, 'abc'); + assert.ok(!concatResult) + batch.apply() + assert.equal(concatResult, 'abc') - MockCommand.prototype.apply = function () { /* empty fn */ }; - MockCommand.prototype.unapply = function () { concatResult += this.text; }; - concatResult = ''; - assert.ok(!concatResult); - batch.unapply(); - assert.equal(concatResult, 'cba'); + MockCommand.prototype.apply = function () { /* empty fn */ } + MockCommand.prototype.unapply = function () { concatResult += this.text } + concatResult = '' + assert.ok(!concatResult) + batch.unapply() + assert.equal(concatResult, 'cba') - MockCommand.prototype.unapply = function () { /* empty fn */ }; - }); -}); + MockCommand.prototype.unapply = function () { /* empty fn */ } + }) +}) diff --git a/cypress/integration/unit/math.js b/cypress/integration/unit/math.js index 5b90935d..a0de7a97 100644 --- a/cypress/integration/unit/math.js +++ b/cypress/integration/unit/math.js @@ -1,106 +1,106 @@ -import { NS } from '../../../instrumented/svgcanvas/namespaces.js'; -import * as math from '../../../instrumented/svgcanvas/math.js'; +import { NS } from '../../../instrumented/svgcanvas/namespaces.js' +import * as math from '../../../instrumented/svgcanvas/math.js' describe('math', function () { - const svg = document.createElementNS(NS.SVG, 'svg'); + const svg = document.createElementNS(NS.SVG, 'svg') it('Test svgedit.math package', function () { - assert.ok(math); - assert.ok(math.transformPoint); - assert.ok(math.isIdentity); - assert.ok(math.matrixMultiply); - assert.equal(typeof math.transformPoint, typeof function () { /* empty fn */ }); - assert.equal(typeof math.isIdentity, typeof function () { /* empty fn */ }); - assert.equal(typeof math.matrixMultiply, typeof function () { /* empty fn */ }); - }); + assert.ok(math) + assert.ok(math.transformPoint) + assert.ok(math.isIdentity) + assert.ok(math.matrixMultiply) + assert.equal(typeof math.transformPoint, typeof function () { /* empty fn */ }) + assert.equal(typeof math.isIdentity, typeof function () { /* empty fn */ }) + assert.equal(typeof math.matrixMultiply, typeof function () { /* empty fn */ }) + }) it('Test svgedit.math.transformPoint() function', function () { - const { transformPoint } = math; + const { transformPoint } = math - const m = svg.createSVGMatrix(); - m.a = 1; m.b = 0; - m.c = 0; m.d = 1; - m.e = 0; m.f = 0; - let pt = transformPoint(100, 200, m); - assert.equal(pt.x, 100); - assert.equal(pt.y, 200); + const m = svg.createSVGMatrix() + m.a = 1; m.b = 0 + m.c = 0; m.d = 1 + m.e = 0; m.f = 0 + let pt = transformPoint(100, 200, m) + assert.equal(pt.x, 100) + assert.equal(pt.y, 200) - m.e = 300; m.f = 400; - pt = transformPoint(100, 200, m); - assert.equal(pt.x, 400); - assert.equal(pt.y, 600); + m.e = 300; m.f = 400 + pt = transformPoint(100, 200, m) + assert.equal(pt.x, 400) + assert.equal(pt.y, 600) - m.a = 0.5; m.b = 0.75; - m.c = 1.25; m.d = 2; - pt = transformPoint(100, 200, m); - assert.equal(pt.x, 100 * m.a + 200 * m.c + m.e); - assert.equal(pt.y, 100 * m.b + 200 * m.d + m.f); - }); + m.a = 0.5; m.b = 0.75 + m.c = 1.25; m.d = 2 + pt = transformPoint(100, 200, m) + assert.equal(pt.x, 100 * m.a + 200 * m.c + m.e) + assert.equal(pt.y, 100 * m.b + 200 * m.d + m.f) + }) it('Test svgedit.math.isIdentity() function', function () { - assert.ok(math.isIdentity(svg.createSVGMatrix())); + assert.ok(math.isIdentity(svg.createSVGMatrix())) - const m = svg.createSVGMatrix(); - m.a = 1; m.b = 0; - m.c = 0; m.d = 1; - m.e = 0; m.f = 0; - assert.ok(math.isIdentity(m)); - }); + const m = svg.createSVGMatrix() + m.a = 1; m.b = 0 + m.c = 0; m.d = 1 + m.e = 0; m.f = 0 + assert.ok(math.isIdentity(m)) + }) it('Test svgedit.math.matrixMultiply() function', function () { - const mult = math.matrixMultiply; - const { isIdentity } = math; + const mult = math.matrixMultiply + const { isIdentity } = math // translate there and back - const tr1 = svg.createSVGMatrix().translate(100, 50); - const tr2 = svg.createSVGMatrix().translate(-90, 0); - const tr3 = svg.createSVGMatrix().translate(-10, -50); - let I = mult(tr1, tr2, tr3); - assert.ok(isIdentity(I), 'Expected identity matrix when translating there and back'); + const tr1 = svg.createSVGMatrix().translate(100, 50) + const tr2 = svg.createSVGMatrix().translate(-90, 0) + const tr3 = svg.createSVGMatrix().translate(-10, -50) + let I = mult(tr1, tr2, tr3) + assert.ok(isIdentity(I), 'Expected identity matrix when translating there and back') // rotate there and back // TODO: currently Mozilla fails this when rotating back at -50 and then -40 degrees // (b and c are *almost* zero, but not zero) - const rotThere = svg.createSVGMatrix().rotate(90); - const rotBack = svg.createSVGMatrix().rotate(-90); // TODO: set this to -50 - const rotBackMore = svg.createSVGMatrix().rotate(0); // TODO: set this to -40 - I = mult(rotThere, rotBack, rotBackMore); - assert.ok(isIdentity(I), 'Expected identity matrix when rotating there and back'); + const rotThere = svg.createSVGMatrix().rotate(90) + const rotBack = svg.createSVGMatrix().rotate(-90) // TODO: set this to -50 + const rotBackMore = svg.createSVGMatrix().rotate(0) // TODO: set this to -40 + I = mult(rotThere, rotBack, rotBackMore) + assert.ok(isIdentity(I), 'Expected identity matrix when rotating there and back') // scale up and down - const scaleUp = svg.createSVGMatrix().scale(4); - const scaleDown = svg.createSVGMatrix().scaleNonUniform(0.25, 1); - const scaleDownMore = svg.createSVGMatrix().scaleNonUniform(1, 0.25); - I = mult(scaleUp, scaleDown, scaleDownMore); - assert.ok(isIdentity(I), 'Expected identity matrix when scaling up and down'); + const scaleUp = svg.createSVGMatrix().scale(4) + const scaleDown = svg.createSVGMatrix().scaleNonUniform(0.25, 1) + const scaleDownMore = svg.createSVGMatrix().scaleNonUniform(1, 0.25) + I = mult(scaleUp, scaleDown, scaleDownMore) + assert.ok(isIdentity(I), 'Expected identity matrix when scaling up and down') // test multiplication with its inverse - I = mult(rotThere, rotThere.inverse()); - assert.ok(isIdentity(I), 'Expected identity matrix when multiplying a matrix by its inverse'); - I = mult(rotThere.inverse(), rotThere); - assert.ok(isIdentity(I), 'Expected identity matrix when multiplying a matrix by its inverse'); - }); + I = mult(rotThere, rotThere.inverse()) + assert.ok(isIdentity(I), 'Expected identity matrix when multiplying a matrix by its inverse') + I = mult(rotThere.inverse(), rotThere) + assert.ok(isIdentity(I), 'Expected identity matrix when multiplying a matrix by its inverse') + }) it('Test svgedit.math.transformBox() function', function () { - const { transformBox } = math; + const { transformBox } = math - const m = svg.createSVGMatrix(); - m.a = 1; m.b = 0; - m.c = 0; m.d = 1; - m.e = 0; m.f = 0; + const m = svg.createSVGMatrix() + m.a = 1; m.b = 0 + m.c = 0; m.d = 1 + m.e = 0; m.f = 0 - const r = transformBox(10, 10, 200, 300, m); - assert.equal(r.tl.x, 10); - assert.equal(r.tl.y, 10); - assert.equal(r.tr.x, 210); - assert.equal(r.tr.y, 10); - assert.equal(r.bl.x, 10); - assert.equal(r.bl.y, 310); - assert.equal(r.br.x, 210); - assert.equal(r.br.y, 310); - assert.equal(r.aabox.x, 10); - assert.equal(r.aabox.y, 10); - assert.equal(r.aabox.width, 200); - assert.equal(r.aabox.height, 300); - }); -}); + const r = transformBox(10, 10, 200, 300, m) + assert.equal(r.tl.x, 10) + assert.equal(r.tl.y, 10) + assert.equal(r.tr.x, 210) + assert.equal(r.tr.y, 10) + assert.equal(r.bl.x, 10) + assert.equal(r.bl.y, 310) + assert.equal(r.br.x, 210) + assert.equal(r.br.y, 310) + assert.equal(r.aabox.x, 10) + assert.equal(r.aabox.y, 10) + assert.equal(r.aabox.width, 200) + assert.equal(r.aabox.height, 300) + }) +}) diff --git a/cypress/integration/unit/path.js b/cypress/integration/unit/path.js index 56ac516e..5a5d806e 100644 --- a/cypress/integration/unit/path.js +++ b/cypress/integration/unit/path.js @@ -1,10 +1,10 @@ /* globals SVGPathSeg */ -import 'pathseg'; -import { NS } from '../../../instrumented/svgcanvas/namespaces.js'; -import * as utilities from '../../../instrumented/svgcanvas/utilities.js'; -import * as pathModule from '../../../instrumented/svgcanvas/path.js'; -import { Path, Segment } from '../../../instrumented/svgcanvas/path-method.js'; -import { init as unitsInit } from '../../../instrumented/common/units.js'; +import 'pathseg' +import { NS } from '../../../instrumented/svgcanvas/namespaces.js' +import * as utilities from '../../../instrumented/svgcanvas/utilities.js' +import * as pathModule from '../../../instrumented/svgcanvas/path.js' +import { Path, Segment } from '../../../instrumented/svgcanvas/path-method.js' +import { init as unitsInit } from '../../../instrumented/common/units.js' describe('path', function () { /** @@ -18,165 +18,165 @@ describe('path', function () { * @returns {EditorContexts} */ function getMockContexts (svg) { - svg = svg || document.createElementNS(NS.SVG, 'svg'); - const selectorParentGroup = document.createElementNS(NS.SVG, 'g'); - selectorParentGroup.setAttribute('id', 'selectorParentGroup'); - svg.append(selectorParentGroup); + svg = svg || document.createElementNS(NS.SVG, 'svg') + const selectorParentGroup = document.createElementNS(NS.SVG, 'g') + selectorParentGroup.setAttribute('id', 'selectorParentGroup') + svg.append(selectorParentGroup) return [ /** * @implements {module:path.EditorContext} */ { - getSvgRoot () { return svg; }, - getZoom () { return 1; } + getSvgRoot () { return svg }, + getZoom () { return 1 } }, /** * @implements {module:utilities.EditorContext} */ { - getDOMDocument () { return svg; }, - getDOMContainer () { return svg; }, - getSvgRoot () { return svg; } + getDOMDocument () { return svg }, + getDOMContainer () { return svg }, + getSvgRoot () { return svg } } - ]; + ] } it('Test svgedit.path.replacePathSeg', function () { - const path = document.createElementNS(NS.SVG, 'path'); - path.setAttribute('d', 'M0,0 L10,11 L20,21Z'); + const path = document.createElementNS(NS.SVG, 'path') + path.setAttribute('d', 'M0,0 L10,11 L20,21Z') - const [ mockPathContext, mockUtilitiesContext ] = getMockContexts(); - pathModule.init(mockPathContext); - utilities.init(mockUtilitiesContext); - new Path(path); + const [mockPathContext, mockUtilitiesContext] = getMockContexts() + pathModule.init(mockPathContext) + utilities.init(mockUtilitiesContext) + Path(path) - assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L'); - assert.equal(path.pathSegList.getItem(1).x, 10); - assert.equal(path.pathSegList.getItem(1).y, 11); + assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L') + assert.equal(path.pathSegList.getItem(1).x, 10) + assert.equal(path.pathSegList.getItem(1).y, 11) - pathModule.replacePathSeg(SVGPathSeg.PATHSEG_LINETO_REL, 1, [ 30, 31 ], path); + pathModule.replacePathSeg(SVGPathSeg.PATHSEG_LINETO_REL, 1, [30, 31], path) - assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'l'); - assert.equal(path.pathSegList.getItem(1).x, 30); - assert.equal(path.pathSegList.getItem(1).y, 31); - }); + assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'l') + assert.equal(path.pathSegList.getItem(1).x, 30) + assert.equal(path.pathSegList.getItem(1).y, 31) + }) it('Test svgedit.path.Segment.setType simple', function () { - const path = document.createElementNS(NS.SVG, 'path'); - path.setAttribute('d', 'M0,0 L10,11 L20,21Z'); + const path = document.createElementNS(NS.SVG, 'path') + path.setAttribute('d', 'M0,0 L10,11 L20,21Z') - const [ mockPathContext, mockUtilitiesContext ] = getMockContexts(); - pathModule.init(mockPathContext); - utilities.init(mockUtilitiesContext); - new Path(path); + const [mockPathContext, mockUtilitiesContext] = getMockContexts() + pathModule.init(mockPathContext) + utilities.init(mockUtilitiesContext) + Path(path) - assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L'); - assert.equal(path.pathSegList.getItem(1).x, 10); - assert.equal(path.pathSegList.getItem(1).y, 11); + assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L') + assert.equal(path.pathSegList.getItem(1).x, 10) + assert.equal(path.pathSegList.getItem(1).y, 11) - const segment = new Segment(1, path.pathSegList.getItem(1)); - segment.setType(SVGPathSeg.PATHSEG_LINETO_REL, [ 30, 31 ]); - assert.equal(segment.item.pathSegTypeAsLetter, 'l'); - assert.equal(segment.item.x, 30); - assert.equal(segment.item.y, 31); + const segment = new Segment(1, path.pathSegList.getItem(1)) + segment.setType(SVGPathSeg.PATHSEG_LINETO_REL, [30, 31]) + assert.equal(segment.item.pathSegTypeAsLetter, 'l') + assert.equal(segment.item.x, 30) + assert.equal(segment.item.y, 31) // Also verify that the actual path changed. - assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'l'); - assert.equal(path.pathSegList.getItem(1).x, 30); - assert.equal(path.pathSegList.getItem(1).y, 31); - }); + assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'l') + assert.equal(path.pathSegList.getItem(1).x, 30) + assert.equal(path.pathSegList.getItem(1).y, 31) + }) it('Test svgedit.path.Segment.setType with control points', function () { // Setup the dom for a mock control group. - const svg = document.createElementNS(NS.SVG, 'svg'); - const path = document.createElementNS(NS.SVG, 'path'); - path.setAttribute('d', 'M0,0 C11,12 13,14 15,16 Z'); - svg.append(path); + const svg = document.createElementNS(NS.SVG, 'svg') + const path = document.createElementNS(NS.SVG, 'path') + path.setAttribute('d', 'M0,0 C11,12 13,14 15,16 Z') + svg.append(path) - const [ mockPathContext, mockUtilitiesContext ] = getMockContexts(svg); - pathModule.init(mockPathContext); - utilities.init(mockUtilitiesContext); - const segment = new Segment(1, path.pathSegList.getItem(1)); - segment.path = new Path(path); + const [mockPathContext, mockUtilitiesContext] = getMockContexts(svg) + pathModule.init(mockPathContext) + utilities.init(mockUtilitiesContext) + const segment = new Segment(1, path.pathSegList.getItem(1)) + segment.path = new Path(path) - assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'C'); - assert.equal(path.pathSegList.getItem(1).x1, 11); - assert.equal(path.pathSegList.getItem(1).y1, 12); - assert.equal(path.pathSegList.getItem(1).x2, 13); - assert.equal(path.pathSegList.getItem(1).y2, 14); - assert.equal(path.pathSegList.getItem(1).x, 15); - assert.equal(path.pathSegList.getItem(1).y, 16); + assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'C') + assert.equal(path.pathSegList.getItem(1).x1, 11) + assert.equal(path.pathSegList.getItem(1).y1, 12) + assert.equal(path.pathSegList.getItem(1).x2, 13) + assert.equal(path.pathSegList.getItem(1).y2, 14) + assert.equal(path.pathSegList.getItem(1).x, 15) + assert.equal(path.pathSegList.getItem(1).y, 16) - segment.setType(SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, [ 30, 31, 32, 33, 34, 35 ]); - assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'c'); - assert.equal(path.pathSegList.getItem(1).x1, 32); - assert.equal(path.pathSegList.getItem(1).y1, 33); - assert.equal(path.pathSegList.getItem(1).x2, 34); - assert.equal(path.pathSegList.getItem(1).y2, 35); - assert.equal(path.pathSegList.getItem(1).x, 30); - assert.equal(path.pathSegList.getItem(1).y, 31); - }); + segment.setType(SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, [30, 31, 32, 33, 34, 35]) + assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'c') + assert.equal(path.pathSegList.getItem(1).x1, 32) + assert.equal(path.pathSegList.getItem(1).y1, 33) + assert.equal(path.pathSegList.getItem(1).x2, 34) + assert.equal(path.pathSegList.getItem(1).y2, 35) + assert.equal(path.pathSegList.getItem(1).x, 30) + assert.equal(path.pathSegList.getItem(1).y, 31) + }) it('Test svgedit.path.Segment.move', function () { - const path = document.createElementNS(NS.SVG, 'path'); - path.setAttribute('d', 'M0,0 L10,11 L20,21Z'); + const path = document.createElementNS(NS.SVG, 'path') + path.setAttribute('d', 'M0,0 L10,11 L20,21Z') - const [ mockPathContext, mockUtilitiesContext ] = getMockContexts(); - pathModule.init(mockPathContext); - utilities.init(mockUtilitiesContext); - new Path(path); + const [mockPathContext, mockUtilitiesContext] = getMockContexts() + pathModule.init(mockPathContext) + utilities.init(mockUtilitiesContext) + Path(path) - assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L'); - assert.equal(path.pathSegList.getItem(1).x, 10); - assert.equal(path.pathSegList.getItem(1).y, 11); + assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L') + assert.equal(path.pathSegList.getItem(1).x, 10) + assert.equal(path.pathSegList.getItem(1).y, 11) - const segment = new Segment(1, path.pathSegList.getItem(1)); - segment.move(-3, 4); - assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L'); - assert.equal(path.pathSegList.getItem(1).x, 7); - assert.equal(path.pathSegList.getItem(1).y, 15); - }); + const segment = new Segment(1, path.pathSegList.getItem(1)) + segment.move(-3, 4) + assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L') + assert.equal(path.pathSegList.getItem(1).x, 7) + assert.equal(path.pathSegList.getItem(1).y, 15) + }) it('Test svgedit.path.Segment.moveCtrl', function () { - const path = document.createElementNS(NS.SVG, 'path'); - path.setAttribute('d', 'M0,0 C11,12 13,14 15,16 Z'); + const path = document.createElementNS(NS.SVG, 'path') + path.setAttribute('d', 'M0,0 C11,12 13,14 15,16 Z') - const [ mockPathContext, mockUtilitiesContext ] = getMockContexts(); - pathModule.init(mockPathContext); - utilities.init(mockUtilitiesContext); - new Path(path); + const [mockPathContext, mockUtilitiesContext] = getMockContexts() + pathModule.init(mockPathContext) + utilities.init(mockUtilitiesContext) + Path(path) - assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'C'); - assert.equal(path.pathSegList.getItem(1).x1, 11); - assert.equal(path.pathSegList.getItem(1).y1, 12); - assert.equal(path.pathSegList.getItem(1).x2, 13); - assert.equal(path.pathSegList.getItem(1).y2, 14); - assert.equal(path.pathSegList.getItem(1).x, 15); - assert.equal(path.pathSegList.getItem(1).y, 16); + assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'C') + assert.equal(path.pathSegList.getItem(1).x1, 11) + assert.equal(path.pathSegList.getItem(1).y1, 12) + assert.equal(path.pathSegList.getItem(1).x2, 13) + assert.equal(path.pathSegList.getItem(1).y2, 14) + assert.equal(path.pathSegList.getItem(1).x, 15) + assert.equal(path.pathSegList.getItem(1).y, 16) - const segment = new Segment(1, path.pathSegList.getItem(1)); - segment.moveCtrl(1, 100, -200); - assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'C'); - assert.equal(path.pathSegList.getItem(1).x1, 111); - assert.equal(path.pathSegList.getItem(1).y1, -188); - assert.equal(path.pathSegList.getItem(1).x2, 13); - assert.equal(path.pathSegList.getItem(1).y2, 14); - assert.equal(path.pathSegList.getItem(1).x, 15); - assert.equal(path.pathSegList.getItem(1).y, 16); - }); + const segment = new Segment(1, path.pathSegList.getItem(1)) + segment.moveCtrl(1, 100, -200) + assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'C') + assert.equal(path.pathSegList.getItem(1).x1, 111) + assert.equal(path.pathSegList.getItem(1).y1, -188) + assert.equal(path.pathSegList.getItem(1).x2, 13) + assert.equal(path.pathSegList.getItem(1).y2, 14) + assert.equal(path.pathSegList.getItem(1).x, 15) + assert.equal(path.pathSegList.getItem(1).y, 16) + }) it('Test svgedit.path.convertPath', function () { unitsInit({ - getRoundDigits () { return 5; } - }); + getRoundDigits () { return 5 } + }) - const path = document.createElementNS(NS.SVG, 'path'); - path.setAttribute('d', 'M40,55h20v20'); + const path = document.createElementNS(NS.SVG, 'path') + path.setAttribute('d', 'M40,55h20v20') - const abs = pathModule.convertPath(path); - assert.equal(abs, 'M40,55L60,55L60,75'); + const abs = pathModule.convertPath(path) + assert.equal(abs, 'M40,55L60,55L60,75') - const rel = pathModule.convertPath(path, true); - assert.equal(rel, 'm40,55l20,0l0,20'); - }); -}); + const rel = pathModule.convertPath(path, true) + assert.equal(rel, 'm40,55l20,0l0,20') + }) +}) diff --git a/cypress/integration/unit/recalculate.js b/cypress/integration/unit/recalculate.js index 28290aeb..c646bb58 100644 --- a/cypress/integration/unit/recalculate.js +++ b/cypress/integration/unit/recalculate.js @@ -1,122 +1,121 @@ -import { NS } from '../../../instrumented/svgcanvas/namespaces.js'; -import * as utilities from '../../../instrumented/svgcanvas/utilities.js'; -import * as coords from '../../../instrumented/svgcanvas/coords.js'; -import * as recalculate from '../../../instrumented/svgcanvas/recalculate.js'; - +import { NS } from '../../../instrumented/svgcanvas/namespaces.js' +import * as utilities from '../../../instrumented/svgcanvas/utilities.js' +import * as coords from '../../../instrumented/svgcanvas/coords.js' +import * as recalculate from '../../../instrumented/svgcanvas/recalculate.js' describe('recalculate', function () { - const root = document.createElement('div'); - root.id = 'root'; - root.style.visibility = 'hidden'; + const root = document.createElement('div') + root.id = 'root' + root.style.visibility = 'hidden' - const svgroot = document.createElementNS(NS.SVG, 'svg'); - svgroot.id = 'svgroot'; - root.append(svgroot); - const svg = document.createElementNS(NS.SVG, 'svg'); - svgroot.append(svg); + const svgroot = document.createElementNS(NS.SVG, 'svg') + svgroot.id = 'svgroot' + root.append(svgroot) + const svg = document.createElementNS(NS.SVG, 'svg') + svgroot.append(svg) const dataStorage = { _storage: new WeakMap(), put: function (element, key, obj) { if (!this._storage.has(element)) { - this._storage.set(element, new Map()); + this._storage.set(element, new Map()) } - this._storage.get(element).set(key, obj); + this._storage.get(element).set(key, obj) }, get: function (element, key) { - return this._storage.get(element).get(key); + return this._storage.get(element).get(key) }, has: function (element, key) { - return this._storage.has(element) && this._storage.get(element).has(key); + return this._storage.has(element) && this._storage.get(element).has(key) }, remove: function (element, key) { - const ret = this._storage.get(element).delete(key); + const ret = this._storage.get(element).delete(key) if (!this._storage.get(element).size === 0) { - this._storage.delete(element); + this._storage.delete(element) } - return ret; + return ret } - }; + } - let elemId = 1; + let elemId = 1 /** * Initilize modules to set up the tests. * @returns {void} */ - function setUp() { + function setUp () { utilities.init( /** * @implements {module:utilities.EditorContext} */ { - getSvgRoot() { return svg; }, - getDOMDocument() { return null; }, - getDOMContainer() { return null; }, - getDataStorage() { return dataStorage; } + getSvgRoot () { return svg }, + getDOMDocument () { return null }, + getDOMContainer () { return null }, + getDataStorage () { return dataStorage } } - ); + ) coords.init( /** * @implements {module:coords.EditorContext} */ { - getGridSnapping() { return false; }, - getDrawing() { + getGridSnapping () { return false }, + getDrawing () { return { - getNextId() { return String(elemId++); } - }; + getNextId () { return String(elemId++) } + } }, - getDataStorage() { return dataStorage; } + getDataStorage () { return dataStorage } } - ); + ) recalculate.init( /** * @implements {module:recalculate.EditorContext} */ { - getSvgRoot() { return svg; }, - getStartTransform() { return ''; }, - setStartTransform() { /* empty fn */ }, - getDataStorage() { return dataStorage; } + getSvgRoot () { return svg }, + getStartTransform () { return '' }, + setStartTransform () { /* empty fn */ }, + getDataStorage () { return dataStorage } } - ); + ) } - let elem; + let elem /** * Initialize for tests and set up `rect` element. * @returns {void} */ - function setUpRect() { - setUp(); - elem = document.createElementNS(NS.SVG, 'rect'); - elem.setAttribute('x', '200'); - elem.setAttribute('y', '150'); - elem.setAttribute('width', '250'); - elem.setAttribute('height', '120'); - svg.append(elem); + function setUpRect () { + setUp() + elem = document.createElementNS(NS.SVG, 'rect') + elem.setAttribute('x', '200') + elem.setAttribute('y', '150') + elem.setAttribute('width', '250') + elem.setAttribute('height', '120') + svg.append(elem) } /** * Initialize for tests and set up `text` element with `tspan` child. * @returns {void} */ - function setUpTextWithTspan() { - setUp(); - elem = document.createElementNS(NS.SVG, 'text'); - elem.setAttribute('x', '200'); - elem.setAttribute('y', '150'); + function setUpTextWithTspan () { + setUp() + elem = document.createElementNS(NS.SVG, 'text') + elem.setAttribute('x', '200') + elem.setAttribute('y', '150') - const tspan = document.createElementNS(NS.SVG, 'tspan'); - tspan.setAttribute('x', '200'); - tspan.setAttribute('y', '150'); + const tspan = document.createElementNS(NS.SVG, 'tspan') + tspan.setAttribute('x', '200') + tspan.setAttribute('y', '150') - const theText = 'Foo bar'; - tspan.append(theText); - elem.append(tspan); - svg.append(elem); + const theText = 'Foo bar' + tspan.append(theText) + elem.append(tspan) + svg.append(elem) } /** @@ -125,53 +124,53 @@ describe('recalculate', function () { */ afterEach(() => { while (svg.hasChildNodes()) { - svg.firstChild.remove(); + svg.firstChild.remove() } - }); + }) it('Test recalculateDimensions() on rect with identity matrix', function () { - setUpRect(); - elem.setAttribute('transform', 'matrix(1,0,0,1,0,0)'); + setUpRect() + elem.setAttribute('transform', 'matrix(1,0,0,1,0,0)') - recalculate.recalculateDimensions(elem); + recalculate.recalculateDimensions(elem) // Ensure that the identity matrix is swallowed and the element has no // transform on it. - assert.equal(elem.hasAttribute('transform'), false); - }); + assert.equal(elem.hasAttribute('transform'), false) + }) it('Test recalculateDimensions() on rect with simple translate', function () { - setUpRect(); - elem.setAttribute('transform', 'translate(100,50)'); + setUpRect() + elem.setAttribute('transform', 'translate(100,50)') - recalculate.recalculateDimensions(elem); + recalculate.recalculateDimensions(elem) - assert.equal(elem.hasAttribute('transform'), false); - assert.equal(elem.getAttribute('x'), '300'); - assert.equal(elem.getAttribute('y'), '200'); - assert.equal(elem.getAttribute('width'), '250'); - assert.equal(elem.getAttribute('height'), '120'); - }); + assert.equal(elem.hasAttribute('transform'), false) + assert.equal(elem.getAttribute('x'), '300') + assert.equal(elem.getAttribute('y'), '200') + assert.equal(elem.getAttribute('width'), '250') + assert.equal(elem.getAttribute('height'), '120') + }) it('Test recalculateDimensions() on text w/tspan with simple translate', function () { - setUpTextWithTspan(); - elem.setAttribute('transform', 'translate(100,50)'); + setUpTextWithTspan() + elem.setAttribute('transform', 'translate(100,50)') - recalculate.recalculateDimensions(elem); + recalculate.recalculateDimensions(elem) // Ensure that the identity matrix is swallowed and the element has no // transform on it. - assert.equal(elem.hasAttribute('transform'), false); - assert.equal(elem.getAttribute('x'), '300'); - assert.equal(elem.getAttribute('y'), '200'); + assert.equal(elem.hasAttribute('transform'), false) + assert.equal(elem.getAttribute('x'), '300') + assert.equal(elem.getAttribute('y'), '200') - const tspan = elem.firstElementChild; - assert.equal(tspan.getAttribute('x'), '300'); - assert.equal(tspan.getAttribute('y'), '200'); - }); + const tspan = elem.firstElementChild + assert.equal(tspan.getAttribute('x'), '300') + assert.equal(tspan.getAttribute('y'), '200') + }) // TODO: Since recalculateDimensions() and surrounding code is // probably the largest, most complicated and strange piece of // code in SVG-edit, we need to write a whole lot of unit tests // for it here. -}); +}) diff --git a/cypress/integration/unit/sanitize.js b/cypress/integration/unit/sanitize.js index 02b879be..bb028a2d 100644 --- a/cypress/integration/unit/sanitize.js +++ b/cypress/integration/unit/sanitize.js @@ -1,17 +1,17 @@ -import { NS } from '../../../instrumented/svgcanvas/namespaces.js'; -import * as sanitize from '../../../instrumented/svgcanvas/sanitize.js'; +import { NS } from '../../../instrumented/svgcanvas/namespaces.js' +import * as sanitize from '../../../instrumented/svgcanvas/sanitize.js' describe('sanitize', function () { - const svg = document.createElementNS(NS.SVG, 'svg'); + const svg = document.createElementNS(NS.SVG, 'svg') it('Test sanitizeSvg() strips ws from style attr', function () { - const rect = document.createElementNS(NS.SVG, 'rect'); - rect.setAttribute('style', 'stroke: blue ;\t\tstroke-width :\t\t40;'); + const rect = document.createElementNS(NS.SVG, 'rect') + rect.setAttribute('style', 'stroke: blue ;\t\tstroke-width :\t\t40;') // sanitizeSvg() requires the node to have a parent and a document. - svg.append(rect); - sanitize.sanitizeSvg(rect); + svg.append(rect) + sanitize.sanitizeSvg(rect) - assert.equal(rect.getAttribute('stroke'), 'blue'); - assert.equal(rect.getAttribute('stroke-width'), '40'); - }); -}); + assert.equal(rect.getAttribute('stroke'), 'blue') + assert.equal(rect.getAttribute('stroke-width'), '40') + }) +}) diff --git a/cypress/integration/unit/select.js b/cypress/integration/unit/select.js index 5e796ffa..71e88f5c 100644 --- a/cypress/integration/unit/select.js +++ b/cypress/integration/unit/select.js @@ -1,37 +1,37 @@ -import * as select from '../../../instrumented/svgcanvas/select.js'; -import { NS } from '../../../instrumented/svgcanvas/namespaces.js'; +import * as select from '../../../instrumented/svgcanvas/select.js' +import { NS } from '../../../instrumented/svgcanvas/namespaces.js' describe('select', function () { - const sandbox = document.createElement('div'); - sandbox.id = 'sandbox'; + const sandbox = document.createElement('div') + sandbox.id = 'sandbox' - let svgroot; - let svgContent; + let svgroot + let svgContent const mockConfig = { - dimensions: [ 640, 480 ] - }; + dimensions: [640, 480] + } const dataStorage = { _storage: new WeakMap(), put: function (element, key, obj) { if (!this._storage.has(element)) { - this._storage.set(element, new Map()); + this._storage.set(element, new Map()) } - this._storage.get(element).set(key, obj); + this._storage.get(element).set(key, obj) }, get: function (element, key) { - return this._storage.get(element).get(key); + return this._storage.get(element).get(key) }, has: function (element, key) { - return this._storage.has(element) && this._storage.get(element).has(key); + return this._storage.has(element) && this._storage.get(element).has(key) }, remove: function (element, key) { - const ret = this._storage.get(element).delete(key); + const ret = this._storage.get(element).delete(key) if (!this._storage.get(element).size === 0) { - this._storage.delete(element); + this._storage.delete(element) } - return ret; + return ret } - }; + } /** * @implements {module:select.SVGFactory} @@ -39,16 +39,16 @@ describe('select', function () { const mockSvgCanvas = { curConfig: mockConfig, createSVGElement (jsonMap) { - const elem = document.createElementNS(NS.SVG, jsonMap.element); - Object.entries(jsonMap.attr).forEach(([ attr, value ]) => { - elem.setAttribute(attr, value); - }); - return elem; + const elem = document.createElementNS(NS.SVG, jsonMap.element) + Object.entries(jsonMap.attr).forEach(([attr, value]) => { + elem.setAttribute(attr, value) + }) + return elem }, - getSvgRoot () { return svgroot; }, - getSvgContent () { return svgContent; }, - getDataStorage () { return dataStorage; } - }; + getSvgRoot () { return svgroot }, + getSvgContent () { return svgContent }, + getDataStorage () { return dataStorage } + } /** * Potentially reusable test set-up. @@ -58,13 +58,13 @@ describe('select', function () { svgroot = mockSvgCanvas.createSVGElement({ element: 'svg', attr: { id: 'svgroot' } - }); + }) svgContent = mockSvgCanvas.createSVGElement({ element: 'svg', attr: { id: 'svgcontent' } - }); + }) - svgroot.append(svgContent); + svgroot.append(svgContent) /* const rect = */ svgContent.append( mockSvgCanvas.createSVGElement({ element: 'rect', @@ -76,9 +76,9 @@ describe('select', function () { height: '100' } }) - ); - sandbox.append(svgroot); - }); + ) + sandbox.append(svgroot) + }) /* function setUpWithInit () { @@ -92,61 +92,61 @@ describe('select', function () { */ afterEach(() => { while (sandbox.hasChildNodes()) { - sandbox.firstChild.remove(); + sandbox.firstChild.remove() } - }); + }) it('Test svgedit.select package', function () { - assert.ok(select); - assert.ok(select.Selector); - assert.ok(select.SelectorManager); - assert.ok(select.init); - assert.ok(select.getSelectorManager); - assert.equal(typeof select, typeof {}); - assert.equal(typeof select.Selector, typeof function () { /* empty fn */ }); - assert.equal(typeof select.SelectorManager, typeof function () { /* empty fn */ }); - assert.equal(typeof select.init, typeof function () { /* empty fn */ }); - assert.equal(typeof select.getSelectorManager, typeof function () { /* empty fn */ }); - }); + assert.ok(select) + assert.ok(select.Selector) + assert.ok(select.SelectorManager) + assert.ok(select.init) + assert.ok(select.getSelectorManager) + assert.equal(typeof select, typeof {}) + assert.equal(typeof select.Selector, typeof function () { /* empty fn */ }) + assert.equal(typeof select.SelectorManager, typeof function () { /* empty fn */ }) + assert.equal(typeof select.init, typeof function () { /* empty fn */ }) + assert.equal(typeof select.getSelectorManager, typeof function () { /* empty fn */ }) + }) it('Test Selector DOM structure', function () { - assert.ok(svgroot); - assert.ok(svgroot.hasChildNodes()); + assert.ok(svgroot) + assert.ok(svgroot.hasChildNodes()) // Verify non-existence of Selector DOM nodes - assert.equal(svgroot.childNodes.length, 1); - assert.equal(svgroot.childNodes.item(0), svgContent); - assert.ok(!svgroot.querySelector('#selectorParentGroup')); + assert.equal(svgroot.childNodes.length, 1) + assert.equal(svgroot.childNodes.item(0), svgContent) + assert.ok(!svgroot.querySelector('#selectorParentGroup')) - select.init(mockSvgCanvas); + select.init(mockSvgCanvas) - assert.equal(svgroot.childNodes.length, 3); + assert.equal(svgroot.childNodes.length, 3) // Verify existence of canvas background. - const cb = svgroot.childNodes.item(0); - assert.ok(cb); - assert.equal(cb.id, 'canvasBackground'); + const cb = svgroot.childNodes.item(0) + assert.ok(cb) + assert.equal(cb.id, 'canvasBackground') - assert.ok(svgroot.childNodes.item(1)); - assert.equal(svgroot.childNodes.item(1), svgContent); + assert.ok(svgroot.childNodes.item(1)) + assert.equal(svgroot.childNodes.item(1), svgContent) // Verify existence of selectorParentGroup. - const spg = svgroot.childNodes.item(2); - assert.ok(spg); - assert.equal(svgroot.querySelector('#selectorParentGroup'), spg); - assert.equal(spg.id, 'selectorParentGroup'); - assert.equal(spg.tagName, 'g'); + const spg = svgroot.childNodes.item(2) + assert.ok(spg) + assert.equal(svgroot.querySelector('#selectorParentGroup'), spg) + assert.equal(spg.id, 'selectorParentGroup') + assert.equal(spg.tagName, 'g') // Verify existence of all grip elements. - assert.ok(spg.querySelector('#selectorGrip_resize_nw')); - assert.ok(spg.querySelector('#selectorGrip_resize_n')); - assert.ok(spg.querySelector('#selectorGrip_resize_ne')); - assert.ok(spg.querySelector('#selectorGrip_resize_e')); - assert.ok(spg.querySelector('#selectorGrip_resize_se')); - assert.ok(spg.querySelector('#selectorGrip_resize_s')); - assert.ok(spg.querySelector('#selectorGrip_resize_sw')); - assert.ok(spg.querySelector('#selectorGrip_resize_w')); - assert.ok(spg.querySelector('#selectorGrip_rotateconnector')); - assert.ok(spg.querySelector('#selectorGrip_rotate')); - }); -}); + assert.ok(spg.querySelector('#selectorGrip_resize_nw')) + assert.ok(spg.querySelector('#selectorGrip_resize_n')) + assert.ok(spg.querySelector('#selectorGrip_resize_ne')) + assert.ok(spg.querySelector('#selectorGrip_resize_e')) + assert.ok(spg.querySelector('#selectorGrip_resize_se')) + assert.ok(spg.querySelector('#selectorGrip_resize_s')) + assert.ok(spg.querySelector('#selectorGrip_resize_sw')) + assert.ok(spg.querySelector('#selectorGrip_resize_w')) + assert.ok(spg.querySelector('#selectorGrip_rotateconnector')) + assert.ok(spg.querySelector('#selectorGrip_rotate')) + }) +}) diff --git a/cypress/integration/unit/test1.js b/cypress/integration/unit/test1.js index 1d4e05e2..60f866cd 100644 --- a/cypress/integration/unit/test1.js +++ b/cypress/integration/unit/test1.js @@ -1,5 +1,5 @@ /* eslint-disable max-len, no-console */ -import SvgCanvas from '../../../instrumented/svgcanvas/svgcanvas.js'; +import SvgCanvas from '../../../instrumented/svgcanvas/svgcanvas.js' describe('Basic Module', function () { // helper functions @@ -12,34 +12,34 @@ describe('Basic Module', function () { }; */ - let svgCanvas; + let svgCanvas const // svgroot = document.getElementById('svgroot'), // svgdoc = svgroot.documentElement, - svgns = 'http://www.w3.org/2000/svg'; - const xlinkns = 'http://www.w3.org/1999/xlink'; + svgns = 'http://www.w3.org/2000/svg' + const xlinkns = 'http://www.w3.org/1999/xlink' beforeEach(() => { - document.body.textContent = ''; - const svgEditor = document.createElement('div'); - svgEditor.id = 'svg_editor'; - const svgcanvas = document.createElement('div'); - svgcanvas.style.visibility = 'hidden'; - svgcanvas.id = 'svgcanvas'; - const workarea = document.createElement('div'); - workarea.id = 'workarea'; - workarea.append(svgcanvas); - const toolsLeft = document.createElement('div'); - toolsLeft.id = 'tools_left'; + document.body.textContent = '' + const svgEditor = document.createElement('div') + svgEditor.id = 'svg_editor' + const svgcanvas = document.createElement('div') + svgcanvas.style.visibility = 'hidden' + svgcanvas.id = 'svgcanvas' + const workarea = document.createElement('div') + workarea.id = 'workarea' + workarea.append(svgcanvas) + const toolsLeft = document.createElement('div') + toolsLeft.id = 'tools_left' - svgEditor.append(workarea, toolsLeft); - document.body.append(svgEditor); + svgEditor.append(workarea, toolsLeft) + document.body.append(svgEditor) svgCanvas = new SvgCanvas( document.getElementById('svgcanvas'), { canvas_expansion: 3, - dimensions: [ 640, 480 ], + dimensions: [640, 480], initFill: { color: 'FF0000', // solid red opacity: 1 @@ -53,20 +53,20 @@ describe('Basic Module', function () { imgPath: '../editor/images', langPath: 'locale/', extPath: 'extensions/', - extensions: [ 'ext-arrows.js', 'ext-eyedropper.js' ], + extensions: ['ext-arrows.js', 'ext-eyedropper.js'], initTool: 'select', wireframe: false } - ); - }); + ) + }) it('Test existence of SvgCanvas object', function () { - assert.equal(typeof {}, typeof svgCanvas); - }); + assert.equal(typeof {}, typeof svgCanvas) + }) describe('Path Module', function () { it('Test path conversion from absolute to relative', function () { - const convert = svgCanvas.pathActions.convertPath; + const convert = svgCanvas.pathActions.convertPath // TODO: Test these paths: // "m400.00491,625.01379a1.78688,1.78688 0 1 1-3.57373,0a1.78688,1.78688 0 1 13.57373,0z" @@ -78,36 +78,36 @@ describe('Basic Module', function () { "" + "" + '' - ); + ) - const p1 = document.getElementById('p1'); - const p2 = document.getElementById('p2'); - const dAbs = p1.getAttribute('d'); - const seglist = p1.pathSegList; + const p1 = document.getElementById('p1') + const p2 = document.getElementById('p2') + const dAbs = p1.getAttribute('d') + const seglist = p1.pathSegList - assert.equal(p1.nodeName, 'path', "Expected 'path', got"); + assert.equal(p1.nodeName, 'path', "Expected 'path', got") - assert.equal(seglist.numberOfItems, 4, 'Number of segments before conversion'); + assert.equal(seglist.numberOfItems, 4, 'Number of segments before conversion') // verify segments before conversion - let curseg = seglist.getItem(0); - assert.equal(curseg.pathSegTypeAsLetter.toUpperCase(), 'M', 'Before conversion, segment #1 type'); - curseg = seglist.getItem(1); - assert.equal(curseg.pathSegTypeAsLetter.toUpperCase(), 'L', 'Before conversion, segment #2 type'); - curseg = seglist.getItem(3); - assert.equal(curseg.pathSegTypeAsLetter.toUpperCase(), 'Z', 'Before conversion, segment #3 type' + dAbs); + let curseg = seglist.getItem(0) + assert.equal(curseg.pathSegTypeAsLetter.toUpperCase(), 'M', 'Before conversion, segment #1 type') + curseg = seglist.getItem(1) + assert.equal(curseg.pathSegTypeAsLetter.toUpperCase(), 'L', 'Before conversion, segment #2 type') + curseg = seglist.getItem(3) + assert.equal(curseg.pathSegTypeAsLetter.toUpperCase(), 'Z', 'Before conversion, segment #3 type' + dAbs) // convert and verify segments - let d = convert(p1, true); - assert.equal(d, 'm100,100l100,0l-100,0z', 'Converted path to relative string'); + let d = convert(p1, true) + assert.equal(d, 'm100,100l100,0l-100,0z', 'Converted path to relative string') // TODO: see why this isn't working in SVG-edit - d = convert(p2, true); - console.log('Convert true', d); - d = convert(p2, false); - console.log('Convert false', d); - }); - }); + d = convert(p2, true) + console.log('Convert true', d) + d = convert(p2, false) + console.log('Convert false', d) + }) + }) describe('Import Module', function () { it('Test import use', function () { @@ -118,16 +118,16 @@ describe('Basic Module', function () { "" + "" + '' - ); + ) - const u = document.getElementById('the-use'); - const fu = document.getElementById('foreign-use'); - const nfu = document.getElementById('no-use'); + const u = document.getElementById('the-use') + const fu = document.getElementById('foreign-use') + const nfu = document.getElementById('no-use') - assert.equal((u && u.nodeName), 'use', 'Did not import element'); - assert.equal(fu, null, 'Removed element that had a foreign href'); - assert.equal(nfu, null, 'Removed element that had no href'); - }); + assert.equal((u && u.nodeName), 'use', 'Did not import element') + assert.equal(fu, null, 'Removed element that had a foreign href') + assert.equal(nfu, null, 'Removed element that had no href') + }) // This test shows that an element with an invalid attribute is still parsed in properly // and only the attribute is not imported @@ -136,13 +136,13 @@ describe('Basic Module', function () { '' + 'words' + '' - ); + ) - const t = document.getElementById('the-text'); + const t = document.getElementById('the-text') - assert.equal((t && t.nodeName), 'text', 'Did not import element'); - assert.equal(t.getAttribute('d'), null, 'Imported a with a d attribute'); - }); + assert.equal((t && t.nodeName), 'text', 'Did not import element') + assert.equal(t.getAttribute('d'), null, 'Imported a with a d attribute') + }) // This test makes sure import/export properly handles namespaced attributes it('Test importing/exporting namespaced attributes', function () { @@ -151,22 +151,22 @@ describe('Basic Module', function () { '' + '' + '' - ); - const attrVal = document.getElementById('se_test_elem').getAttributeNS('http://svg-edit.googlecode.com', 'foo'); + ) + const attrVal = document.getElementById('se_test_elem').getAttributeNS('http://svg-edit.googlecode.com', 'foo') - assert.strictEqual(attrVal, 'bar', true, 'Preserved namespaced attribute on import'); + assert.strictEqual(attrVal, 'bar', true, 'Preserved namespaced attribute on import') - const output = svgCanvas.getSvgString(); - const hasXlink = output.includes('xmlns:xlink="http://www.w3.org/1999/xlink"'); - const hasSe = output.includes('xmlns:se='); - const hasFoo = output.includes('xmlns:foo='); - const hasAttr = output.includes('se:foo="bar"'); + const output = svgCanvas.getSvgString() + const hasXlink = output.includes('xmlns:xlink="http://www.w3.org/1999/xlink"') + const hasSe = output.includes('xmlns:se=') + const hasFoo = output.includes('xmlns:foo=') + const hasAttr = output.includes('se:foo="bar"') - assert.equal(hasAttr, true, 'Preserved namespaced attribute on export'); - assert.equal(hasXlink, true, 'Included xlink: xmlns'); - assert.equal(hasSe, true, 'Included se: xmlns'); - assert.equal(hasFoo, false, 'Did not include foo: xmlns'); - }); + assert.equal(hasAttr, true, 'Preserved namespaced attribute on export') + assert.equal(hasXlink, true, 'Included xlink: xmlns') + assert.equal(hasSe, true, 'Included se: xmlns') + assert.equal(hasFoo, false, 'Did not include foo: xmlns') + }) it('Test import math elements inside a foreignObject', function () { /* const set = */ svgCanvas.setSvgString( @@ -179,17 +179,17 @@ describe('Basic Module', function () { '' + '' + '' - ); - const fo = document.getElementById('fo'); + ) + const fo = document.getElementById('fo') // we cannot use getElementById('math') because not all browsers understand MathML and do not know to use the @id attribute // see Bug https://bugs.webkit.org/show_bug.cgi?id=35042 - const math = fo.firstChild; + const math = fo.firstChild - assert.equal(Boolean(math), true, 'Math element exists'); - assert.equal(math.nodeName, 'math', 'Math element has the proper nodeName'); - assert.equal(math.getAttribute('id'), 'm', 'Math element has an id'); - assert.equal(math.namespaceURI, 'http://www.w3.org/1998/Math/MathML', 'Preserved MathML namespace'); - }); + assert.equal(Boolean(math), true, 'Math element exists') + assert.equal(math.nodeName, 'math', 'Math element has the proper nodeName') + assert.equal(math.getAttribute('id'), 'm', 'Math element has an id') + assert.equal(math.namespaceURI, 'http://www.w3.org/1998/Math/MathML', 'Preserved MathML namespace') + }) it('Test importing SVG into existing drawing', function () { /* const doc = */ svgCanvas.setSvgString( @@ -199,23 +199,23 @@ describe('Basic Module', function () { '' + '' + '' - ); + ) svgCanvas.importSvgString( '' + '' + '' + '' - ); + ) - const svgContent = document.getElementById('svgcontent'); - const circles = svgContent.getElementsByTagNameNS(svgns, 'circle'); - const rects = svgContent.getElementsByTagNameNS(svgns, 'rect'); - const ellipses = svgContent.getElementsByTagNameNS(svgns, 'ellipse'); - assert.equal(circles.length, 2, 'Found two circles upon importing'); - assert.equal(rects.length, 1, 'Found one rectangle upon importing'); - assert.equal(ellipses.length, 1, 'Found one ellipse upon importing'); - }); + const svgContent = document.getElementById('svgcontent') + const circles = svgContent.getElementsByTagNameNS(svgns, 'circle') + const rects = svgContent.getElementsByTagNameNS(svgns, 'rect') + const ellipses = svgContent.getElementsByTagNameNS(svgns, 'ellipse') + assert.equal(circles.length, 2, 'Found two circles upon importing') + assert.equal(rects.length, 1, 'Found one rectangle upon importing') + assert.equal(ellipses.length, 1, 'Found one ellipse upon importing') + }) it('Test importing SVG remaps IDs', function () { /* const doc = */ svgCanvas.setSvgString( @@ -226,7 +226,7 @@ describe('Basic Module', function () { '' + '' + '' - ); + ) svgCanvas.importSvgString( '' + @@ -240,24 +240,24 @@ describe('Basic Module', function () { '' + '' + '' - ); + ) - const svgContent = document.getElementById('svgcontent'); - const circles = svgContent.getElementsByTagNameNS(svgns, 'circle'); - const rects = svgContent.getElementsByTagNameNS(svgns, 'rect'); + const svgContent = document.getElementById('svgcontent') + const circles = svgContent.getElementsByTagNameNS(svgns, 'circle') + const rects = svgContent.getElementsByTagNameNS(svgns, 'rect') // ellipses = svgContent.getElementsByTagNameNS(svgns, 'ellipse'), - const defs = svgContent.getElementsByTagNameNS(svgns, 'defs'); + const defs = svgContent.getElementsByTagNameNS(svgns, 'defs') // grads = svgContent.getElementsByTagNameNS(svgns, 'linearGradient'), - const uses = svgContent.getElementsByTagNameNS(svgns, 'use'); - assert.notEqual(circles.item(0).id, 'svg_1', 'Circle not re-identified'); - assert.notEqual(rects.item(0).id, 'svg_3', 'Rectangle not re-identified'); + const uses = svgContent.getElementsByTagNameNS(svgns, 'use') + assert.notEqual(circles.item(0).id, 'svg_1', 'Circle not re-identified') + assert.notEqual(rects.item(0).id, 'svg_3', 'Rectangle not re-identified') // TODO: determine why this test fails in WebKit browsers // assert.equal(grads.length, 1, 'Linear gradient imported'); - const grad = defs.item(0).firstChild; - assert.notEqual(grad.id, 'svg_2', 'Linear gradient not re-identified'); - assert.notEqual(circles.item(0).getAttribute('fill'), 'url(#svg_2)', 'Circle fill value not remapped'); - assert.notEqual(rects.item(0).getAttribute('stroke'), 'url(#svg_2)', 'Rectangle stroke value not remapped'); - assert.notEqual(uses.item(0).getAttributeNS(xlinkns, 'href'), '#svg_3'); - }); - }); -}); + const grad = defs.item(0).firstChild + assert.notEqual(grad.id, 'svg_2', 'Linear gradient not re-identified') + assert.notEqual(circles.item(0).getAttribute('fill'), 'url(#svg_2)', 'Circle fill value not remapped') + assert.notEqual(rects.item(0).getAttribute('stroke'), 'url(#svg_2)', 'Rectangle stroke value not remapped') + assert.notEqual(uses.item(0).getAttributeNS(xlinkns, 'href'), '#svg_3') + }) + }) +}) diff --git a/cypress/integration/unit/units.js b/cypress/integration/unit/units.js index 99e2e7bd..91b1412a 100644 --- a/cypress/integration/unit/units.js +++ b/cypress/integration/unit/units.js @@ -1,4 +1,4 @@ -import * as units from '../../../instrumented/common/units.js'; +import * as units from '../../../instrumented/common/units.js' describe('units', function () { /** @@ -6,86 +6,86 @@ describe('units', function () { * @returns {void} */ beforeEach(() => { - document.body.textContent = ''; - const anchor = document.createElement('div'); - anchor.id = 'anchor'; - anchor.style.visibility = 'hidden'; + document.body.textContent = '' + const anchor = document.createElement('div') + anchor.id = 'anchor' + anchor.style.visibility = 'hidden' - const elementsContainer = document.createElement('div'); - elementsContainer.id = 'elementsContainer'; + const elementsContainer = document.createElement('div') + elementsContainer.id = 'elementsContainer' - const uniqueId = document.createElement('div'); - uniqueId.id = 'uniqueId'; - uniqueId.style.visibility = 'hidden'; + const uniqueId = document.createElement('div') + uniqueId.id = 'uniqueId' + uniqueId.style.visibility = 'hidden' - const nonUniqueId = document.createElement('div'); - nonUniqueId.id = 'nonUniqueId'; - nonUniqueId.style.visibility = 'hidden'; + const nonUniqueId = document.createElement('div') + nonUniqueId.id = 'nonUniqueId' + nonUniqueId.style.visibility = 'hidden' - elementsContainer.append(uniqueId, nonUniqueId); + elementsContainer.append(uniqueId, nonUniqueId) - document.body.append(anchor, elementsContainer); + document.body.append(anchor, elementsContainer) units.init( /** * @implements {module:units.ElementContainer} */ { - getBaseUnit () { return 'cm'; }, - getHeight () { return 600; }, - getWidth () { return 800; }, - getRoundDigits () { return 4; }, - getElement (elementId) { return document.getElementById(elementId); } + getBaseUnit () { return 'cm' }, + getHeight () { return 600 }, + getWidth () { return 800 }, + getRoundDigits () { return 4 }, + getElement (elementId) { return document.getElementById(elementId) } } - ); - }); + ) + }) it('Test svgedit.units package', function () { - assert.ok(units); - assert.equal(typeof units, typeof {}); - }); + assert.ok(units) + assert.equal(typeof units, typeof {}) + }) it('Test svgedit.units.shortFloat()', function () { - assert.ok(units.shortFloat); - assert.equal(typeof units.shortFloat, typeof function () { /* empty fn */ }); + assert.ok(units.shortFloat) + assert.equal(typeof units.shortFloat, typeof function () { /* empty fn */ }) - const { shortFloat } = units; - assert.equal(shortFloat(0.00000001), 0); - assert.equal(shortFloat(1), 1); - assert.equal(shortFloat(3.45678), 3.4568); - assert.equal(shortFloat(1.23443), 1.2344); - assert.equal(shortFloat(1.23455), 1.2346); - }); + const { shortFloat } = units + assert.equal(shortFloat(0.00000001), 0) + assert.equal(shortFloat(1), 1) + assert.equal(shortFloat(3.45678), 3.4568) + assert.equal(shortFloat(1.23443), 1.2344) + assert.equal(shortFloat(1.23455), 1.2346) + }) it('Test svgedit.units.isValidUnit()', function () { - assert.ok(units.isValidUnit); - assert.equal(typeof units.isValidUnit, typeof function () { /* empty fn */ }); + assert.ok(units.isValidUnit) + assert.equal(typeof units.isValidUnit, typeof function () { /* empty fn */ }) - const { isValidUnit } = units; - assert.ok(isValidUnit('0')); - assert.ok(isValidUnit('1')); - assert.ok(isValidUnit('1.1')); - assert.ok(isValidUnit('-1.1')); - assert.ok(isValidUnit('.6mm')); - assert.ok(isValidUnit('-.6cm')); - assert.ok(isValidUnit('6000in')); - assert.ok(isValidUnit('6px')); - assert.ok(isValidUnit('6.3pc')); - assert.ok(isValidUnit('-0.4em')); - assert.ok(isValidUnit('-0.ex')); - assert.ok(isValidUnit('40.123%')); + const { isValidUnit } = units + assert.ok(isValidUnit('0')) + assert.ok(isValidUnit('1')) + assert.ok(isValidUnit('1.1')) + assert.ok(isValidUnit('-1.1')) + assert.ok(isValidUnit('.6mm')) + assert.ok(isValidUnit('-.6cm')) + assert.ok(isValidUnit('6000in')) + assert.ok(isValidUnit('6px')) + assert.ok(isValidUnit('6.3pc')) + assert.ok(isValidUnit('-0.4em')) + assert.ok(isValidUnit('-0.ex')) + assert.ok(isValidUnit('40.123%')) - assert.equal(isValidUnit('id', 'uniqueId', document.getElementById('uniqueId')), true); - assert.equal(isValidUnit('id', 'newId', document.getElementById('uniqueId')), true); - assert.equal(isValidUnit('id', 'uniqueId'), false); - assert.equal(isValidUnit('id', 'uniqueId', document.getElementById('nonUniqueId')), false); - }); + assert.equal(isValidUnit('id', 'uniqueId', document.getElementById('uniqueId')), true) + assert.equal(isValidUnit('id', 'newId', document.getElementById('uniqueId')), true) + assert.equal(isValidUnit('id', 'uniqueId'), false) + assert.equal(isValidUnit('id', 'uniqueId', document.getElementById('nonUniqueId')), false) + }) it('Test svgedit.units.convertUnit()', function () { - assert.ok(units.convertUnit); - assert.equal(typeof units.convertUnit, typeof function () { /* empty fn */ }); + assert.ok(units.convertUnit) + assert.equal(typeof units.convertUnit, typeof function () { /* empty fn */ }) // cm in default setup - assert.equal(units.convertUnit(42), 1.1113); - assert.equal(units.convertUnit(42, 'px'), 42); - }); -}); + assert.equal(units.convertUnit(42), 1.1113) + assert.equal(units.convertUnit(42, 'px'), 42) + }) +}) diff --git a/cypress/integration/unit/utilities-bbox.js b/cypress/integration/unit/utilities-bbox.js index 40786c82..1f43f78e 100644 --- a/cypress/integration/unit/utilities-bbox.js +++ b/cypress/integration/unit/utilities-bbox.js @@ -1,12 +1,13 @@ -import 'pathseg'; +import 'pathseg' -import { NS } from '../../../instrumented/svgcanvas/namespaces.js'; -import * as utilities from '../../../instrumented/svgcanvas/utilities.js'; -import * as math from '../../../instrumented/svgcanvas/math.js'; -import * as path from '../../../instrumented/svgcanvas/path.js'; -import setAssertionMethods from '../../support/assert-close.js'; +import { NS } from '../../../instrumented/svgcanvas/namespaces.js' +import * as utilities from '../../../instrumented/svgcanvas/utilities.js' +import * as math from '../../../instrumented/svgcanvas/math.js' +import * as path from '../../../instrumented/svgcanvas/path.js' +import setAssertionMethods from '../../support/assert-close.js' -chai.use(setAssertionMethods); +// eslint-disable-next-line +chai.use(setAssertionMethods) describe('utilities bbox', function () { /** @@ -15,13 +16,13 @@ describe('utilities bbox', function () { * @returns {SVGElement} */ function mockCreateSVGElement (jsonMap) { - const elem = document.createElementNS(NS.SVG, jsonMap.element); - Object.entries(jsonMap.attr).forEach(([ attr, value ]) => { - elem.setAttribute(attr, value); - }); - return elem; + const elem = document.createElementNS(NS.SVG, jsonMap.element) + Object.entries(jsonMap.attr).forEach(([attr, value]) => { + elem.setAttribute(attr, value) + }) + return elem } - let mockaddSVGElemensFromJsonCallCount = 0; + let mockaddSVGElemensFromJsonCallCount = 0 /** * Mock of {@link module:utilities.EditorContext#addSVGElemensFromJson}. @@ -29,435 +30,435 @@ describe('utilities bbox', function () { * @returns {SVGElement} */ function mockaddSVGElemensFromJson (json) { - const elem = mockCreateSVGElement(json); - svgroot.append(elem); - mockaddSVGElemensFromJsonCallCount++; - return elem; + const elem = mockCreateSVGElement(json) + svgroot.append(elem) + mockaddSVGElemensFromJsonCallCount++ + return elem } const mockPathActions = { resetOrientation (pth) { - if (utilities.isNullish(pth) || pth.nodeName !== 'path') { return false; } - const tlist = pth.transform.baseVal; - const m = math.transformListToTransform(tlist).matrix; - tlist.clear(); - pth.removeAttribute('transform'); - const segList = pth.pathSegList; + if (utilities.isNullish(pth) || pth.nodeName !== 'path') { return false } + const tlist = pth.transform.baseVal + const m = math.transformListToTransform(tlist).matrix + tlist.clear() + pth.removeAttribute('transform') + const segList = pth.pathSegList - const len = segList.numberOfItems; + const len = segList.numberOfItems // let lastX, lastY; for (let i = 0; i < len; ++i) { - const seg = segList.getItem(i); - const type = seg.pathSegType; - if (type === 1) { continue; } + const seg = segList.getItem(i) + const type = seg.pathSegType + if (type === 1) { continue } const pts = []; - [ '', 1, 2 ].forEach(function (n) { - const x = seg['x' + n]; const y = seg['y' + n]; + ['', 1, 2].forEach(function (n) { + const x = seg['x' + n]; const y = seg['y' + n] if (x !== undefined && y !== undefined) { - const pt = math.transformPoint(x, y, m); - pts.splice(pts.length, 0, pt.x, pt.y); + const pt = math.transformPoint(x, y, m) + pts.splice(pts.length, 0, pt.x, pt.y) } - }); - path.replacePathSeg(type, i, pts, pth); + }) + path.replacePathSeg(type, i, pts, pth) } - return undefined; + return undefined } - }; + } - const EPSILON = 0.001; + const EPSILON = 0.001 - let svgroot; + let svgroot beforeEach(() => { - document.body.textContent = ''; + document.body.textContent = '' // const svg = document.createElementNS(NS.SVG, 'svg'); - const sandbox = document.createElement('div'); - sandbox.id = 'sandbox'; - document.body.append(sandbox); + const sandbox = document.createElement('div') + sandbox.id = 'sandbox' + document.body.append(sandbox) svgroot = mockCreateSVGElement({ element: 'svg', attr: { id: 'svgroot' } - }); - sandbox.append(svgroot); + }) + sandbox.append(svgroot) const mockSvgCanvas = { createSVGElement (jsonMap) { - const elem = document.createElementNS(NS.SVG, jsonMap.element); - Object.entries(jsonMap.attr).forEach(([ attr, value ]) => { - elem.setAttribute(attr, value); - }); - return elem; + const elem = document.createElementNS(NS.SVG, jsonMap.element) + Object.entries(jsonMap.attr).forEach(([attr, value]) => { + elem.setAttribute(attr, value) + }) + return elem }, - getSvgRoot () { return svgroot; } - }; + getSvgRoot () { return svgroot } + } - path.init(mockSvgCanvas); - mockaddSVGElemensFromJsonCallCount = 0; - }); + path.init(mockSvgCanvas) + mockaddSVGElemensFromJsonCallCount = 0 + }) it('Test svgedit.utilities package', function () { - assert.ok(utilities); - assert.ok(utilities.getBBoxWithTransform); - assert.ok(utilities.getStrokedBBox); - assert.ok(utilities.getRotationAngleFromTransformList); - assert.ok(utilities.getRotationAngle); - }); + assert.ok(utilities) + assert.ok(utilities.getBBoxWithTransform) + assert.ok(utilities.getStrokedBBox) + assert.ok(utilities.getRotationAngleFromTransformList) + assert.ok(utilities.getRotationAngle) + }) it('Test getBBoxWithTransform and no transform', function () { - const { getBBoxWithTransform } = utilities; + const { getBBoxWithTransform } = utilities let elem = mockCreateSVGElement({ element: 'path', attr: { id: 'path', d: 'M0,1 L2,3' } - }); - svgroot.append(elem); - let bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 2, height: 2 }); - assert.equal(mockaddSVGElemensFromJsonCallCount, 0); - elem.remove(); + }) + svgroot.append(elem) + let bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 2, height: 2 }) + assert.equal(mockaddSVGElemensFromJsonCallCount, 0) + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '0', y: '1', width: '5', height: '10' } - }); - svgroot.append(elem); - bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - assert.equal(mockaddSVGElemensFromJsonCallCount, 0); - elem.remove(); + }) + svgroot.append(elem) + bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }) + assert.equal(mockaddSVGElemensFromJsonCallCount, 0) + elem.remove() elem = mockCreateSVGElement({ element: 'line', attr: { id: 'line', x1: '0', y1: '1', x2: '5', y2: '6' } - }); - svgroot.append(elem); - bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }); - assert.equal(mockaddSVGElemensFromJsonCallCount, 0); - elem.remove(); + }) + svgroot.append(elem) + bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }) + assert.equal(mockaddSVGElemensFromJsonCallCount, 0) + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '0', y: '1', width: '5', height: '10' } - }); + }) const g = mockCreateSVGElement({ element: 'g', attr: {} - }); - g.append(elem); - svgroot.append(g); - bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - assert.equal(mockaddSVGElemensFromJsonCallCount, 0); - g.remove(); - }); + }) + g.append(elem) + svgroot.append(g) + bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }) + assert.equal(mockaddSVGElemensFromJsonCallCount, 0) + g.remove() + }) it('Test getBBoxWithTransform and a rotation transform', function () { - const { getBBoxWithTransform } = utilities; + const { getBBoxWithTransform } = utilities let elem = mockCreateSVGElement({ element: 'path', attr: { id: 'path', d: 'M10,10 L20,20', transform: 'rotate(45 10,10)' } - }); - svgroot.append(elem); - let bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions); - assert.close(bbox.x, 10, EPSILON); - assert.close(bbox.y, 10, EPSILON); - assert.close(bbox.width, 0, EPSILON); - assert.close(bbox.height, Math.sqrt(100 + 100), EPSILON); - elem.remove(); + }) + svgroot.append(elem) + let bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions) + assert.close(bbox.x, 10, EPSILON) + assert.close(bbox.y, 10, EPSILON) + assert.close(bbox.width, 0, EPSILON) + assert.close(bbox.height, Math.sqrt(100 + 100), EPSILON) + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '10', y: '10', width: '10', height: '20', transform: 'rotate(90 15,20)' } - }); - svgroot.append(elem); - bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions); - assert.close(bbox.x, 5, EPSILON); - assert.close(bbox.y, 15, EPSILON); - assert.close(bbox.width, 20, EPSILON); - assert.close(bbox.height, 10, EPSILON); - assert.equal(mockaddSVGElemensFromJsonCallCount, 1); - elem.remove(); + }) + svgroot.append(elem) + bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions) + assert.close(bbox.x, 5, EPSILON) + assert.close(bbox.y, 15, EPSILON) + assert.close(bbox.width, 20, EPSILON) + assert.close(bbox.height, 10, EPSILON) + assert.equal(mockaddSVGElemensFromJsonCallCount, 1) + elem.remove() - const rect = { x: 10, y: 10, width: 10, height: 20 }; - const angle = 45; - const origin = { x: 15, y: 20 }; + const rect = { x: 10, y: 10, width: 10, height: 20 } + const angle = 45 + const origin = { x: 15, y: 20 } elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect2', x: rect.x, y: rect.y, width: rect.width, height: rect.height, transform: 'rotate(' + angle + ' ' + origin.x + ',' + origin.y + ')' } - }); - svgroot.append(elem); - mockaddSVGElemensFromJsonCallCount = 0; - bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions); - const r2 = rotateRect(rect, angle, origin); - assert.close(bbox.x, r2.x, EPSILON, 'rect2 x is ' + r2.x); - assert.close(bbox.y, r2.y, EPSILON, 'rect2 y is ' + r2.y); - assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width); - assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height); - assert.equal(mockaddSVGElemensFromJsonCallCount, 0); - elem.remove(); + }) + svgroot.append(elem) + mockaddSVGElemensFromJsonCallCount = 0 + bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions) + const r2 = rotateRect(rect, angle, origin) + assert.close(bbox.x, r2.x, EPSILON, 'rect2 x is ' + r2.x) + assert.close(bbox.y, r2.y, EPSILON, 'rect2 y is ' + r2.y) + assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width) + assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height) + assert.equal(mockaddSVGElemensFromJsonCallCount, 0) + elem.remove() // Same as previous but wrapped with g and the transform is with the g. elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect3', x: rect.x, y: rect.y, width: rect.width, height: rect.height } - }); + }) const g = mockCreateSVGElement({ element: 'g', attr: { transform: 'rotate(' + angle + ' ' + origin.x + ',' + origin.y + ')' } - }); - g.append(elem); - svgroot.append(g); - mockaddSVGElemensFromJsonCallCount = 0; - bbox = getBBoxWithTransform(g, mockaddSVGElemensFromJson, mockPathActions); - assert.close(bbox.x, r2.x, EPSILON, 'rect2 x is ' + r2.x); - assert.close(bbox.y, r2.y, EPSILON, 'rect2 y is ' + r2.y); - assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width); - assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height); - assert.equal(mockaddSVGElemensFromJsonCallCount, 0); - g.remove(); + }) + g.append(elem) + svgroot.append(g) + mockaddSVGElemensFromJsonCallCount = 0 + bbox = getBBoxWithTransform(g, mockaddSVGElemensFromJson, mockPathActions) + assert.close(bbox.x, r2.x, EPSILON, 'rect2 x is ' + r2.x) + assert.close(bbox.y, r2.y, EPSILON, 'rect2 y is ' + r2.y) + assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width) + assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height) + assert.equal(mockaddSVGElemensFromJsonCallCount, 0) + g.remove() elem = mockCreateSVGElement({ element: 'ellipse', attr: { id: 'ellipse1', cx: '100', cy: '100', rx: '50', ry: '50', transform: 'rotate(45 100,100)' } - }); - svgroot.append(elem); - mockaddSVGElemensFromJsonCallCount = 0; - bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions); + }) + svgroot.append(elem) + mockaddSVGElemensFromJsonCallCount = 0 + bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions) /** @todo: Review these test the BBox algorithm is using the bezier control points to calculate the bounding box. Should be 50, 50, 100, 100. */ // assert.ok(bbox.x > 45 && bbox.x <= 50); - assert.ok(bbox.y > 45 && bbox.y <= 50); + assert.ok(bbox.y > 45 && bbox.y <= 50) // assert.ok(bbox.width >= 100 && bbox.width < 110); // assert.ok(bbox.height >= 100 && bbox.height < 110); - assert.equal(mockaddSVGElemensFromJsonCallCount, 1); - elem.remove(); - }); + assert.equal(mockaddSVGElemensFromJsonCallCount, 1) + elem.remove() + }) it('Test getBBoxWithTransform with rotation and matrix transforms', function () { - const { getBBoxWithTransform } = utilities; + const { getBBoxWithTransform } = utilities - let tx = 10; // tx right - let ty = 10; // tx down - let txInRotatedSpace = Math.sqrt(tx * tx + ty * ty); // translate in rotated 45 space. - let tyInRotatedSpace = 0; - let matrix = 'matrix(1,0,0,1,' + txInRotatedSpace + ',' + tyInRotatedSpace + ')'; + let tx = 10 // tx right + let ty = 10 // tx down + let txInRotatedSpace = Math.sqrt(tx * tx + ty * ty) // translate in rotated 45 space. + let tyInRotatedSpace = 0 + let matrix = 'matrix(1,0,0,1,' + txInRotatedSpace + ',' + tyInRotatedSpace + ')' let elem = mockCreateSVGElement({ element: 'path', attr: { id: 'path', d: 'M10,10 L20,20', transform: 'rotate(45 10,10) ' + matrix } - }); - svgroot.append(elem); - let bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions); - assert.close(bbox.x, 10 + tx, EPSILON); - assert.close(bbox.y, 10 + ty, EPSILON); - assert.close(bbox.width, 0, EPSILON); - assert.close(bbox.height, Math.sqrt(100 + 100), EPSILON); - elem.remove(); + }) + svgroot.append(elem) + let bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions) + assert.close(bbox.x, 10 + tx, EPSILON) + assert.close(bbox.y, 10 + ty, EPSILON) + assert.close(bbox.width, 0, EPSILON) + assert.close(bbox.height, Math.sqrt(100 + 100), EPSILON) + elem.remove() - txInRotatedSpace = tx; // translate in rotated 90 space. - tyInRotatedSpace = -ty; - matrix = 'matrix(1,0,0,1,' + txInRotatedSpace + ',' + tyInRotatedSpace + ')'; + txInRotatedSpace = tx // translate in rotated 90 space. + tyInRotatedSpace = -ty + matrix = 'matrix(1,0,0,1,' + txInRotatedSpace + ',' + tyInRotatedSpace + ')' elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '10', y: '10', width: '10', height: '20', transform: 'rotate(90 15,20) ' + matrix } - }); - svgroot.append(elem); - bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions); - assert.close(bbox.x, 5 + tx, EPSILON); - assert.close(bbox.y, 15 + ty, EPSILON); - assert.close(bbox.width, 20, EPSILON); - assert.close(bbox.height, 10, EPSILON); - elem.remove(); + }) + svgroot.append(elem) + bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions) + assert.close(bbox.x, 5 + tx, EPSILON) + assert.close(bbox.y, 15 + ty, EPSILON) + assert.close(bbox.width, 20, EPSILON) + assert.close(bbox.height, 10, EPSILON) + elem.remove() - const rect = { x: 10, y: 10, width: 10, height: 20 }; - const angle = 45; - const origin = { x: 15, y: 20 }; - tx = 10; // tx right - ty = 10; // tx down - txInRotatedSpace = Math.sqrt(tx * tx + ty * ty); // translate in rotated 45 space. - tyInRotatedSpace = 0; - matrix = 'matrix(1,0,0,1,' + txInRotatedSpace + ',' + tyInRotatedSpace + ')'; + const rect = { x: 10, y: 10, width: 10, height: 20 } + const angle = 45 + const origin = { x: 15, y: 20 } + tx = 10 // tx right + ty = 10 // tx down + txInRotatedSpace = Math.sqrt(tx * tx + ty * ty) // translate in rotated 45 space. + tyInRotatedSpace = 0 + matrix = 'matrix(1,0,0,1,' + txInRotatedSpace + ',' + tyInRotatedSpace + ')' elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect2', x: rect.x, y: rect.y, width: rect.width, height: rect.height, transform: 'rotate(' + angle + ' ' + origin.x + ',' + origin.y + ') ' + matrix } - }); - svgroot.append(elem); - bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions); - const r2 = rotateRect(rect, angle, origin); - assert.close(bbox.x, r2.x + tx, EPSILON, 'rect2 x is ' + r2.x); - assert.close(bbox.y, r2.y + ty, EPSILON, 'rect2 y is ' + r2.y); - assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width); - assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height); - elem.remove(); + }) + svgroot.append(elem) + bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions) + const r2 = rotateRect(rect, angle, origin) + assert.close(bbox.x, r2.x + tx, EPSILON, 'rect2 x is ' + r2.x) + assert.close(bbox.y, r2.y + ty, EPSILON, 'rect2 y is ' + r2.y) + assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width) + assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height) + elem.remove() // Same as previous but wrapped with g and the transform is with the g. elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect3', x: rect.x, y: rect.y, width: rect.width, height: rect.height } - }); + }) const g = mockCreateSVGElement({ element: 'g', attr: { transform: 'rotate(' + angle + ' ' + origin.x + ',' + origin.y + ') ' + matrix } - }); - g.append(elem); - svgroot.append(g); - bbox = getBBoxWithTransform(g, mockaddSVGElemensFromJson, mockPathActions); - assert.close(bbox.x, r2.x + tx, EPSILON, 'rect2 x is ' + r2.x); - assert.close(bbox.y, r2.y + ty, EPSILON, 'rect2 y is ' + r2.y); - assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width); - assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height); - g.remove(); + }) + g.append(elem) + svgroot.append(g) + bbox = getBBoxWithTransform(g, mockaddSVGElemensFromJson, mockPathActions) + assert.close(bbox.x, r2.x + tx, EPSILON, 'rect2 x is ' + r2.x) + assert.close(bbox.y, r2.y + ty, EPSILON, 'rect2 y is ' + r2.y) + assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width) + assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height) + g.remove() elem = mockCreateSVGElement({ element: 'ellipse', attr: { id: 'ellipse1', cx: '100', cy: '100', rx: '50', ry: '50', transform: 'rotate(45 100,100) ' + matrix } - }); - svgroot.append(elem); - bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions); + }) + svgroot.append(elem) + bbox = getBBoxWithTransform(elem, mockaddSVGElemensFromJson, mockPathActions) /** @todo: the BBox algorithm is using the bezier control points to calculate the bounding box. Should be 50, 50, 100, 100. */ // assert.ok(bbox.x > 45 + tx && bbox.x <= 50 + tx); - assert.ok(bbox.y > 45 + ty && bbox.y <= 50 + ty); + assert.ok(bbox.y > 45 + ty && bbox.y <= 50 + ty) // assert.ok(bbox.width >= 100 && bbox.width < 110); // assert.ok(bbox.height >= 100 && bbox.height < 110); - elem.remove(); - }); + elem.remove() + }) it('Test getStrokedBBox with stroke-width 10', function () { - const { getStrokedBBox } = utilities; + const { getStrokedBBox } = utilities - const strokeWidth = 10; + const strokeWidth = 10 let elem = mockCreateSVGElement({ element: 'path', attr: { id: 'path', d: 'M0,1 L2,3', 'stroke-width': strokeWidth } - }); - svgroot.append(elem); - let bbox = getStrokedBBox([ elem ], mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 2 + strokeWidth, height: 2 + strokeWidth }); - elem.remove(); + }) + svgroot.append(elem) + let bbox = getStrokedBBox([elem], mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 2 + strokeWidth, height: 2 + strokeWidth }) + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '0', y: '1', width: '5', height: '10', 'stroke-width': strokeWidth } - }); - svgroot.append(elem); - bbox = getStrokedBBox([ elem ], mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 5 + strokeWidth, height: 10 + strokeWidth }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getStrokedBBox([elem], mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 5 + strokeWidth, height: 10 + strokeWidth }) + elem.remove() elem = mockCreateSVGElement({ element: 'line', attr: { id: 'line', x1: '0', y1: '1', x2: '5', y2: '6', 'stroke-width': strokeWidth } - }); - svgroot.append(elem); - bbox = getStrokedBBox([ elem ], mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 5 + strokeWidth, height: 5 + strokeWidth }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getStrokedBBox([elem], mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 5 + strokeWidth, height: 5 + strokeWidth }) + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '0', y: '1', width: '5', height: '10', 'stroke-width': strokeWidth } - }); + }) const g = mockCreateSVGElement({ element: 'g', attr: {} - }); - g.append(elem); - svgroot.append(g); - bbox = getStrokedBBox([ elem ], mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 5 + strokeWidth, height: 10 + strokeWidth }); - g.remove(); - }); + }) + g.append(elem) + svgroot.append(g) + bbox = getStrokedBBox([elem], mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 5 + strokeWidth, height: 10 + strokeWidth }) + g.remove() + }) it("Test getStrokedBBox with stroke-width 'none'", function () { - const { getStrokedBBox } = utilities; + const { getStrokedBBox } = utilities let elem = mockCreateSVGElement({ element: 'path', attr: { id: 'path', d: 'M0,1 L2,3', 'stroke-width': 'none' } - }); - svgroot.append(elem); - let bbox = getStrokedBBox([ elem ], mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 2, height: 2 }); - elem.remove(); + }) + svgroot.append(elem) + let bbox = getStrokedBBox([elem], mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 2, height: 2 }) + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '0', y: '1', width: '5', height: '10', 'stroke-width': 'none' } - }); - svgroot.append(elem); - bbox = getStrokedBBox([ elem ], mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getStrokedBBox([elem], mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }) + elem.remove() elem = mockCreateSVGElement({ element: 'line', attr: { id: 'line', x1: '0', y1: '1', x2: '5', y2: '6', 'stroke-width': 'none' } - }); - svgroot.append(elem); - bbox = getStrokedBBox([ elem ], mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getStrokedBBox([elem], mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }) + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '0', y: '1', width: '5', height: '10', 'stroke-width': 'none' } - }); + }) const g = mockCreateSVGElement({ element: 'g', attr: {} - }); - g.append(elem); - svgroot.append(g); - bbox = getStrokedBBox([ elem ], mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - g.remove(); - }); + }) + g.append(elem) + svgroot.append(g) + bbox = getStrokedBBox([elem], mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }) + g.remove() + }) it('Test getStrokedBBox with no stroke-width attribute', function () { - const { getStrokedBBox } = utilities; + const { getStrokedBBox } = utilities let elem = mockCreateSVGElement({ element: 'path', attr: { id: 'path', d: 'M0,1 L2,3' } - }); - svgroot.append(elem); - let bbox = getStrokedBBox([ elem ], mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 2, height: 2 }); - elem.remove(); + }) + svgroot.append(elem) + let bbox = getStrokedBBox([elem], mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 2, height: 2 }) + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '0', y: '1', width: '5', height: '10' } - }); - svgroot.append(elem); - bbox = getStrokedBBox([ elem ], mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getStrokedBBox([elem], mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }) + elem.remove() elem = mockCreateSVGElement({ element: 'line', attr: { id: 'line', x1: '0', y1: '1', x2: '5', y2: '6' } - }); - svgroot.append(elem); - bbox = getStrokedBBox([ elem ], mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getStrokedBBox([elem], mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }) + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '0', y: '1', width: '5', height: '10' } - }); + }) const g = mockCreateSVGElement({ element: 'g', attr: {} - }); - g.append(elem); - svgroot.append(g); - bbox = getStrokedBBox([ elem ], mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - g.remove(); - }); + }) + g.append(elem) + svgroot.append(g) + bbox = getStrokedBBox([elem], mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }) + g.remove() + }) /** * Returns radians for degrees. @@ -465,7 +466,7 @@ describe('utilities bbox', function () { * @returns {Float} */ function radians (degrees) { - return degrees * Math.PI / 180; + return degrees * Math.PI / 180 } /** @@ -477,15 +478,15 @@ describe('utilities bbox', function () { */ function rotatePoint (point, angle, origin) { if (!origin) { - origin = { x: 0, y: 0 }; + origin = { x: 0, y: 0 } } - const x = point.x - origin.x; - const y = point.y - origin.y; - const theta = radians(angle); + const x = point.x - origin.x + const y = point.y - origin.y + const theta = radians(angle) return { x: x * Math.cos(theta) + y * Math.sin(theta) + origin.x, y: x * Math.sin(theta) + y * Math.cos(theta) + origin.y - }; + } } /** * @@ -495,21 +496,21 @@ describe('utilities bbox', function () { * @returns {module:utilities.BBoxObject} */ function rotateRect (rect, angle, origin) { - const tl = rotatePoint({ x: rect.x, y: rect.y }, angle, origin); - const tr = rotatePoint({ x: rect.x + rect.width, y: rect.y }, angle, origin); - const br = rotatePoint({ x: rect.x + rect.width, y: rect.y + rect.height }, angle, origin); - const bl = rotatePoint({ x: rect.x, y: rect.y + rect.height }, angle, origin); + const tl = rotatePoint({ x: rect.x, y: rect.y }, angle, origin) + const tr = rotatePoint({ x: rect.x + rect.width, y: rect.y }, angle, origin) + const br = rotatePoint({ x: rect.x + rect.width, y: rect.y + rect.height }, angle, origin) + const bl = rotatePoint({ x: rect.x, y: rect.y + rect.height }, angle, origin) - const minx = Math.min(tl.x, tr.x, bl.x, br.x); - const maxx = Math.max(tl.x, tr.x, bl.x, br.x); - const miny = Math.min(tl.y, tr.y, bl.y, br.y); - const maxy = Math.max(tl.y, tr.y, bl.y, br.y); + const minx = Math.min(tl.x, tr.x, bl.x, br.x) + const maxx = Math.max(tl.x, tr.x, bl.x, br.x) + const miny = Math.min(tl.y, tr.y, bl.y, br.y) + const maxy = Math.max(tl.y, tr.y, bl.y, br.y) return { x: minx, y: miny, width: (maxx - minx), height: (maxy - miny) - }; + } } -}); +}) diff --git a/cypress/integration/unit/utilities-performance.js b/cypress/integration/unit/utilities-performance.js index b095b8f2..386f4b6d 100644 --- a/cypress/integration/unit/utilities-performance.js +++ b/cypress/integration/unit/utilities-performance.js @@ -1,17 +1,17 @@ /* eslint-disable max-len, no-console */ -import 'pathseg'; +import 'pathseg' -import { NS } from '../../../instrumented/svgcanvas/namespaces.js'; -import * as utilities from '../../../instrumented/svgcanvas/utilities.js'; -import * as math from '../../../instrumented/svgcanvas/math.js'; +import { NS } from '../../../instrumented/svgcanvas/namespaces.js' +import * as utilities from '../../../instrumented/svgcanvas/utilities.js' +import * as math from '../../../instrumented/svgcanvas/math.js' describe('utilities performance', function () { - let currentLayer; let groupWithMatrixTransform; let textWithMatrixTransform; + let currentLayer; let groupWithMatrixTransform; let textWithMatrixTransform beforeEach(() => { - document.body.textContent = ''; - const style = document.createElement('style'); - style.id = 'styleoverrides'; - style.media = 'screen'; + document.body.textContent = '' + const style = document.createElement('style') + style.id = 'styleoverrides' + style.media = 'screen' style.textContent = ` #svgcanvas svg * { cursor: move; @@ -19,9 +19,9 @@ describe('utilities performance', function () { } #svgcanvas svg { cursor: default - }`; + }` - document.head.append(style); + document.head.append(style) const editor = new DOMParser().parseFromString(`
@@ -64,14 +64,14 @@ describe('utilities performance', function () {
-
`, 'application/xml'); - const newNode = document.body.ownerDocument.importNode(editor.documentElement, true); - document.body.append(newNode); + `, 'application/xml') + const newNode = document.body.ownerDocument.importNode(editor.documentElement, true) + document.body.append(newNode) - currentLayer = document.getElementById('layer1'); - groupWithMatrixTransform = document.getElementById('svg_group_with_matrix_transform'); - textWithMatrixTransform = document.getElementById('svg_text_with_matrix_transform'); - }); + currentLayer = document.getElementById('layer1') + groupWithMatrixTransform = document.getElementById('svg_group_with_matrix_transform') + textWithMatrixTransform = document.getElementById('svg_text_with_matrix_transform') + }) /** * Create an SVG element for a mock. @@ -79,11 +79,11 @@ describe('utilities performance', function () { * @returns {SVGElement} */ function mockCreateSVGElement (jsonMap) { - const elem = document.createElementNS(NS.SVG, jsonMap.element); - Object.entries(jsonMap.attr).forEach(([ attr, value ]) => { - elem.setAttribute(attr, value); - }); - return elem; + const elem = document.createElementNS(NS.SVG, jsonMap.element) + Object.entries(jsonMap.attr).forEach(([attr, value]) => { + elem.setAttribute(attr, value) + }) + return elem } /** @@ -92,9 +92,9 @@ describe('utilities performance', function () { * @returns {SVGElement} */ function mockaddSVGElemensFromJson (json) { - const elem = mockCreateSVGElement(json); - currentLayer.append(elem); - return elem; + const elem = mockCreateSVGElement(json) + currentLayer.append(elem) + return elem } /** @@ -104,49 +104,49 @@ describe('utilities performance', function () { * @returns {void} */ function fillDocumentByCloningElement (elem, count) { - const elemId = elem.getAttribute('id') + '-'; + const elemId = elem.getAttribute('id') + '-' for (let index = 0; index < count; index++) { - const clone = elem.cloneNode(true); // t: deep clone + const clone = elem.cloneNode(true) // t: deep clone // Make sure you set a unique ID like a real document. - clone.setAttribute('id', elemId + index); - const { parentNode } = elem; - parentNode.append(clone); + clone.setAttribute('id', elemId + index) + const { parentNode } = elem + parentNode.append(clone) } } const mockPathActions = { resetOrientation (path) { - if (utilities.isNullish(path) || path.nodeName !== 'path') { return false; } - const tlist = path.transform.baseVal; - const m = math.transformListToTransform(tlist).matrix; - tlist.clear(); - path.removeAttribute('transform'); - const segList = path.pathSegList; + if (utilities.isNullish(path) || path.nodeName !== 'path') { return false } + const tlist = path.transform.baseVal + const m = math.transformListToTransform(tlist).matrix + tlist.clear() + path.removeAttribute('transform') + const segList = path.pathSegList - const len = segList.numberOfItems; + const len = segList.numberOfItems // let lastX, lastY; for (let i = 0; i < len; ++i) { - const seg = segList.getItem(i); - const type = seg.pathSegType; + const seg = segList.getItem(i) + const type = seg.pathSegType if (type === 1) { - continue; + continue } const pts = []; - [ '', 1, 2 ].forEach(function (n) { - const x = seg['x' + n]; - const y = seg['y' + n]; + ['', 1, 2].forEach(function (n) { + const x = seg['x' + n] + const y = seg['y' + n] if (x !== undefined && y !== undefined) { - const pt = math.transformPoint(x, y, m); - pts.splice(pts.length, 0, pt.x, pt.y); + const pt = math.transformPoint(x, y, m) + pts.splice(pts.length, 0, pt.x, pt.y) } - }); + }) // path.replacePathSeg(type, i, pts, path); } - return undefined; + return undefined } - }; + } // ////////////////////////////////////////////////////////// // Performance times with various browsers on Macbook 2011 8MB RAM OS X El Capitan 10.11.4 @@ -180,57 +180,57 @@ describe('utilities performance', function () { // Pass2 svgCanvas.getStrokedBBox total ms 17, ave ms 0.2, min/max 0 23 it('Test svgCanvas.getStrokedBBox() performance with matrix transforms', function () { - const { getStrokedBBox } = utilities; - const { children } = currentLayer; + const { getStrokedBBox } = utilities + const { children } = currentLayer - let lastTime; let now; - let min = Number.MAX_VALUE; - let max = 0; - let total = 0; + let lastTime; let now + let min = Number.MAX_VALUE + let max = 0 + let total = 0 - fillDocumentByCloningElement(groupWithMatrixTransform, 50); - fillDocumentByCloningElement(textWithMatrixTransform, 50); + fillDocumentByCloningElement(groupWithMatrixTransform, 50) + fillDocumentByCloningElement(textWithMatrixTransform, 50) // The first pass through all elements is slower. - const count = children.length; - const start = lastTime = now = Date.now(); + const count = children.length + const start = lastTime = now = Date.now() // Skip the first child which is the title. for (let index = 1; index < count; index++) { - const child = children[index]; - /* const obj = */ getStrokedBBox([ child ], mockaddSVGElemensFromJson, mockPathActions); - now = Date.now(); const delta = now - lastTime; lastTime = now; - total += delta; - min = Math.min(min, delta); - max = Math.max(max, delta); + const child = children[index] + /* const obj = */ getStrokedBBox([child], mockaddSVGElemensFromJson, mockPathActions) + now = Date.now(); const delta = now - lastTime; lastTime = now + total += delta + min = Math.min(min, delta) + max = Math.max(max, delta) } - total = lastTime - start; - const ave = total / count; - assert.isBelow(ave, 20, 'svgedit.utilities.getStrokedBBox average execution time is less than 20 ms'); - console.log('Pass1 svgCanvas.getStrokedBBox total ms ' + total + ', ave ms ' + ave.toFixed(1) + ',\t min/max ' + min + ' ' + max); + total = lastTime - start + const ave = total / count + assert.isBelow(ave, 20, 'svgedit.utilities.getStrokedBBox average execution time is less than 20 ms') + console.log('Pass1 svgCanvas.getStrokedBBox total ms ' + total + ', ave ms ' + ave.toFixed(1) + ',\t min/max ' + min + ' ' + max) return new Promise((resolve) => { // The second pass is two to ten times faster. setTimeout(function () { - const ct = children.length; + const ct = children.length - const strt = lastTime = now = Date.now(); + const strt = lastTime = now = Date.now() // Skip the first child which is the title. for (let index = 1; index < ct; index++) { - const child = children[index]; - /* const obj = */ getStrokedBBox([ child ], mockaddSVGElemensFromJson, mockPathActions); - now = Date.now(); const delta = now - lastTime; lastTime = now; - total += delta; - min = Math.min(min, delta); - max = Math.max(max, delta); + const child = children[index] + /* const obj = */ getStrokedBBox([child], mockaddSVGElemensFromJson, mockPathActions) + now = Date.now(); const delta = now - lastTime; lastTime = now + total += delta + min = Math.min(min, delta) + max = Math.max(max, delta) } - total = lastTime - strt; - const avg = total / ct; - assert.isBelow(avg, 2, 'svgedit.utilities.getStrokedBBox average execution time is less than 1 ms'); - console.log('Pass2 svgCanvas.getStrokedBBox total ms ' + total + ', ave ms ' + avg.toFixed(1) + ',\t min/max ' + min + ' ' + max); + total = lastTime - strt + const avg = total / ct + assert.isBelow(avg, 2, 'svgedit.utilities.getStrokedBBox average execution time is less than 1 ms') + console.log('Pass2 svgCanvas.getStrokedBBox total ms ' + total + ', ave ms ' + avg.toFixed(1) + ',\t min/max ' + min + ' ' + max) - resolve(); - }); - }); - }); -}); + resolve() + }) + }) + }) +}) diff --git a/cypress/integration/unit/utilities.js b/cypress/integration/unit/utilities.js index aa1616cc..5d8a2cc1 100644 --- a/cypress/integration/unit/utilities.js +++ b/cypress/integration/unit/utilities.js @@ -1,5 +1,5 @@ -import * as utilities from '../../../instrumented/svgcanvas/utilities.js'; -import { NS } from '../../../instrumented/svgcanvas/namespaces.js'; +import * as utilities from '../../../instrumented/svgcanvas/utilities.js' +import { NS } from '../../../instrumented/svgcanvas/namespaces.js' describe('utilities', function () { /** @@ -8,11 +8,11 @@ describe('utilities', function () { * @returns {SVGElement} */ function mockCreateSVGElement (jsonMap) { - const elem = document.createElementNS(NS.SVG, jsonMap.element); - Object.entries(jsonMap.attr).forEach(([ attr, value ]) => { - elem.setAttribute(attr, value); - }); - return elem; + const elem = document.createElementNS(NS.SVG, jsonMap.element) + Object.entries(jsonMap.attr).forEach(([attr, value]) => { + elem.setAttribute(attr, value) + }) + return elem } /** * Adds SVG Element per parameters and appends to root. @@ -20,225 +20,225 @@ describe('utilities', function () { * @returns {SVGElement} */ function mockaddSVGElemensFromJson (json) { - const elem = mockCreateSVGElement(json); - svgroot.append(elem); - return elem; + const elem = mockCreateSVGElement(json) + svgroot.append(elem) + return elem } - const mockPathActions = { resetOrientation () { /* empty fn */ } }; - let mockHistorySubCommands = []; + const mockPathActions = { resetOrientation () { /* empty fn */ } } + let mockHistorySubCommands = [] const mockHistory = { BatchCommand: class { addSubCommand (cmd) { - mockHistorySubCommands.push(cmd); + mockHistorySubCommands.push(cmd) } }, RemoveElementCommand: class { // Longhand needed since used as a constructor constructor (elem, nextSibling, parent) { - this.elem = elem; - this.nextSibling = nextSibling; - this.parent = parent; + this.elem = elem + this.nextSibling = nextSibling + this.parent = parent } }, InsertElementCommand: class { constructor (path) { // Longhand needed since used as a constructor - this.path = path; + this.path = path } } - }; + } const mockCount = { clearSelection: 0, addToSelection: 0, addCommandToHistory: 0 - }; + } /** * Increments clear seleciton count for mock test. * @returns {void} */ function mockClearSelection () { - mockCount.clearSelection++; + mockCount.clearSelection++ } /** * Increments add selection count for mock test. * @returns {void} */ function mockAddToSelection () { - mockCount.addToSelection++; + mockCount.addToSelection++ } /** * Increments add command to history count for mock test. * @returns {void} */ function mockAddCommandToHistory () { - mockCount.addCommandToHistory++; + mockCount.addCommandToHistory++ } - let svg; let svgroot; + let svg; let svgroot beforeEach(() => { - document.body.textContent = ''; + document.body.textContent = '' - mockHistorySubCommands = []; - mockCount.clearSelection = 0; - mockCount.addToSelection = 0; - mockCount.addCommandToHistory = 0; + mockHistorySubCommands = [] + mockCount.clearSelection = 0 + mockCount.addToSelection = 0 + mockCount.addCommandToHistory = 0 - const sandbox = document.createElement('div'); - svg = document.createElementNS(NS.SVG, 'svg'); + const sandbox = document.createElement('div') + svg = document.createElementNS(NS.SVG, 'svg') svgroot = mockCreateSVGElement({ element: 'svg', attr: { id: 'svgroot' } - }); - sandbox.append(svgroot); - document.body.append(sandbox); - }); + }) + sandbox.append(svgroot) + document.body.append(sandbox) + }) it('Test svgedit.utilities package', function () { - assert.ok(utilities); - assert.ok(utilities.toXml); - assert.equal(typeof utilities.toXml, typeof function () { /* empty fn */ }); - }); + assert.ok(utilities) + assert.ok(utilities.toXml) + assert.equal(typeof utilities.toXml, typeof function () { /* empty fn */ }) + }) it('Test svgedit.utilities.toXml() function', function () { - const { toXml } = utilities; + const { toXml } = utilities - assert.equal(toXml('a'), 'a'); - assert.equal(toXml('ABC_'), 'ABC_'); - assert.equal(toXml('PB&J'), 'PB&J'); - assert.equal(toXml('2 < 5'), '2 < 5'); - assert.equal(toXml('5 > 2'), '5 > 2'); - assert.equal(toXml('\'<&>"'), ''<&>"'); - }); + assert.equal(toXml('a'), 'a') + assert.equal(toXml('ABC_'), 'ABC_') + assert.equal(toXml('PB&J'), 'PB&J') + assert.equal(toXml('2 < 5'), '2 < 5') + assert.equal(toXml('5 > 2'), '5 > 2') + assert.equal(toXml('\'<&>"'), ''<&>"') + }) it('Test svgedit.utilities.encode64() function', function () { - const { encode64 } = utilities; + const { encode64 } = utilities - assert.equal(encode64('abcdef'), 'YWJjZGVm'); - assert.equal(encode64('12345'), 'MTIzNDU='); - assert.equal(encode64(' '), 'IA=='); - assert.equal(encode64('`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?'), 'YH4hQCMkJV4mKigpLV89K1t7XX1cfDs6JyIsPC4+Lz8='); - }); + assert.equal(encode64('abcdef'), 'YWJjZGVm') + assert.equal(encode64('12345'), 'MTIzNDU=') + assert.equal(encode64(' '), 'IA==') + assert.equal(encode64('`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?'), 'YH4hQCMkJV4mKigpLV89K1t7XX1cfDs6JyIsPC4+Lz8=') + }) it('Test svgedit.utilities.decode64() function', function () { - const { decode64 } = utilities; + const { decode64 } = utilities - assert.equal(decode64('YWJjZGVm'), 'abcdef'); - assert.equal(decode64('MTIzNDU='), '12345'); - assert.equal(decode64('IA=='), ' '); - assert.equal(decode64('YH4hQCMkJV4mKigpLV89K1t7XX1cfDs6JyIsPC4+Lz8='), '`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?'); - }); + assert.equal(decode64('YWJjZGVm'), 'abcdef') + assert.equal(decode64('MTIzNDU='), '12345') + assert.equal(decode64('IA=='), ' ') + assert.equal(decode64('YH4hQCMkJV4mKigpLV89K1t7XX1cfDs6JyIsPC4+Lz8='), '`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?') + }) it('Test svgedit.utilities.convertToXMLReferences() function', function () { - const convert = utilities.convertToXMLReferences; - assert.equal(convert('ABC'), 'ABC'); + const convert = utilities.convertToXMLReferences + assert.equal(convert('ABC'), 'ABC') // assert.equal(convert('�BC'), 'ÀBC'); - }); + }) it('Test svgedit.utilities.bboxToObj() function', function () { - const { bboxToObj } = utilities; + const { bboxToObj } = utilities - const rect = svg.createSVGRect(); - rect.x = 1; - rect.y = 2; - rect.width = 3; - rect.height = 4; + const rect = svg.createSVGRect() + rect.x = 1 + rect.y = 2 + rect.width = 3 + rect.height = 4 - const obj = bboxToObj(rect); - assert.equal(typeof obj, typeof {}); - assert.equal(obj.x, 1); - assert.equal(obj.y, 2); - assert.equal(obj.width, 3); - assert.equal(obj.height, 4); - }); + const obj = bboxToObj(rect) + assert.equal(typeof obj, typeof {}) + assert.equal(obj.x, 1) + assert.equal(obj.y, 2) + assert.equal(obj.width, 3) + assert.equal(obj.height, 4) + }) it('Test getUrlFromAttr', function () { - assert.equal(utilities.getUrlFromAttr('url(#foo)'), '#foo'); - assert.equal(utilities.getUrlFromAttr('url(somefile.svg#foo)'), 'somefile.svg#foo'); - assert.equal(utilities.getUrlFromAttr('url("#foo")'), '#foo'); - assert.equal(utilities.getUrlFromAttr('url("#foo")'), '#foo'); - }); + assert.equal(utilities.getUrlFromAttr('url(#foo)'), '#foo') + assert.equal(utilities.getUrlFromAttr('url(somefile.svg#foo)'), 'somefile.svg#foo') + assert.equal(utilities.getUrlFromAttr('url("#foo")'), '#foo') + assert.equal(utilities.getUrlFromAttr('url("#foo")'), '#foo') + }) it('Test getPathDFromSegments', function () { - const { getPathDFromSegments } = utilities; + const { getPathDFromSegments } = utilities - const doc = utilities.text2xml(''); - const path = doc.createElementNS(NS.SVG, 'path'); - path.setAttribute('d', 'm0,0l5,0l0,5l-5,0l0,-5z'); + const doc = utilities.text2xml('') + const path = doc.createElementNS(NS.SVG, 'path') + path.setAttribute('d', 'm0,0l5,0l0,5l-5,0l0,-5z') let d = getPathDFromSegments([ - [ 'M', [ 1, 2 ] ], - [ 'Z', [] ] - ]); - assert.equal(d, 'M1,2 Z'); + ['M', [1, 2]], + ['Z', []] + ]) + assert.equal(d, 'M1,2 Z') d = getPathDFromSegments([ - [ 'M', [ 1, 2 ] ], - [ 'M', [ 3, 4 ] ], - [ 'Z', [] ] - ]); - assert.equal(d, 'M1,2 M3,4 Z'); + ['M', [1, 2]], + ['M', [3, 4]], + ['Z', []] + ]) + assert.equal(d, 'M1,2 M3,4 Z') d = getPathDFromSegments([ - [ 'M', [ 1, 2 ] ], - [ 'C', [ 3, 4, 5, 6 ] ], - [ 'Z', [] ] - ]); - assert.equal(d, 'M1,2 C3,4 5,6 Z'); - }); + ['M', [1, 2]], + ['C', [3, 4, 5, 6]], + ['Z', []] + ]) + assert.equal(d, 'M1,2 C3,4 5,6 Z') + }) it('Test getPathDFromElement', function () { - const { getPathDFromElement } = utilities; + const { getPathDFromElement } = utilities let elem = mockCreateSVGElement({ element: 'path', attr: { id: 'path', d: 'M0,1 Z' } - }); - svgroot.append(elem); - assert.equal(getPathDFromElement(elem), 'M0,1 Z'); - elem.remove(); + }) + svgroot.append(elem) + assert.equal(getPathDFromElement(elem), 'M0,1 Z') + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '0', y: '1', width: '5', height: '10' } - }); - svgroot.append(elem); - assert.equal(getPathDFromElement(elem), 'M0,1 L5,1 L5,11 L0,11 L0,1 Z'); - elem.remove(); + }) + svgroot.append(elem) + assert.equal(getPathDFromElement(elem), 'M0,1 L5,1 L5,11 L0,11 L0,1 Z') + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'roundrect', x: '0', y: '1', rx: '2', ry: '3', width: '10', height: '11' } - }); - svgroot.append(elem); - const closeEnough = /M0,4 C0,2.3\d* 0.9\d*,1 2,1 L8,1 C9.0\d*,1 10,2.3\d* 10,4 L10,9 C10,10.6\d* 9.0\d*,12 8,12 L2,12 C0.9\d*,12 0,10.6\d* 0,9 L0,4 Z/; - assert.equal(closeEnough.test(getPathDFromElement(elem)), true); - elem.remove(); + }) + svgroot.append(elem) + const closeEnough = /M0,4 C0,2.3\d* 0.9\d*,1 2,1 L8,1 C9.0\d*,1 10,2.3\d* 10,4 L10,9 C10,10.6\d* 9.0\d*,12 8,12 L2,12 C0.9\d*,12 0,10.6\d* 0,9 L0,4 Z/ + assert.equal(closeEnough.test(getPathDFromElement(elem)), true) + elem.remove() elem = mockCreateSVGElement({ element: 'line', attr: { id: 'line', x1: '0', y1: '1', x2: '5', y2: '6' } - }); - svgroot.append(elem); - assert.equal(getPathDFromElement(elem), 'M0,1L5,6'); - elem.remove(); + }) + svgroot.append(elem) + assert.equal(getPathDFromElement(elem), 'M0,1L5,6') + elem.remove() elem = mockCreateSVGElement({ element: 'circle', attr: { id: 'circle', cx: '10', cy: '11', rx: '5', ry: '10' } - }); - svgroot.append(elem); - assert.equal(getPathDFromElement(elem), 'M5,11 C5,5.475138121546961 7.237569060773481,1 10,1 C12.762430939226519,1 15,5.475138121546961 15,11 C15,16.524861878453038 12.762430939226519,21 10,21 C7.237569060773481,21 5,16.524861878453038 5,11 Z'); - elem.remove(); + }) + svgroot.append(elem) + assert.equal(getPathDFromElement(elem), 'M5,11 C5,5.475138121546961 7.237569060773481,1 10,1 C12.762430939226519,1 15,5.475138121546961 15,11 C15,16.524861878453038 12.762430939226519,21 10,21 C7.237569060773481,21 5,16.524861878453038 5,11 Z') + elem.remove() elem = mockCreateSVGElement({ element: 'polyline', attr: { id: 'polyline', points: '0,1 5,1 5,11 0,11' } - }); - svgroot.append(elem); - assert.equal(getPathDFromElement(elem), 'M0,1 5,1 5,11 0,11'); - elem.remove(); + }) + svgroot.append(elem) + assert.equal(getPathDFromElement(elem), 'M0,1 5,1 5,11 0,11') + elem.remove() - assert.equal(getPathDFromElement({ tagName: 'something unknown' }), undefined); - }); + assert.equal(getPathDFromElement({ tagName: 'something unknown' }), undefined) + }) it('Test getBBoxOfElementAsPath', function () { /** @@ -246,88 +246,88 @@ describe('utilities', function () { * @type {module:utilities.getBBoxOfElementAsPath} */ function getBBoxOfElementAsPath (elem, addSVGElemensFromJson, pathActions) { - const bbox = utilities.getBBoxOfElementAsPath(elem, addSVGElemensFromJson, pathActions); - return utilities.bboxToObj(bbox); // need this for assert.equal() to work. + const bbox = utilities.getBBoxOfElementAsPath(elem, addSVGElemensFromJson, pathActions) + return utilities.bboxToObj(bbox) // need this for assert.equal() to work. } let elem = mockCreateSVGElement({ element: 'path', attr: { id: 'path', d: 'M0,1 Z' } - }); - svgroot.append(elem); - let bbox = getBBoxOfElementAsPath(elem, mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 0, height: 0 }); - elem.remove(); + }) + svgroot.append(elem) + let bbox = getBBoxOfElementAsPath(elem, mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 0, height: 0 }) + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '0', y: '1', width: '5', height: '10' } - }); - svgroot.append(elem); - bbox = getBBoxOfElementAsPath(elem, mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getBBoxOfElementAsPath(elem, mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }) + elem.remove() elem = mockCreateSVGElement({ element: 'line', attr: { id: 'line', x1: '0', y1: '1', x2: '5', y2: '6' } - }); - svgroot.append(elem); - bbox = getBBoxOfElementAsPath(elem, mockaddSVGElemensFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getBBoxOfElementAsPath(elem, mockaddSVGElemensFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }) + elem.remove() // TODO: test element with transform. Need resetOrientation above to be working or mock it. - }); + }) it('Test convertToPath rect', function () { - const { convertToPath } = utilities; + const { convertToPath } = utilities const attrs = { fill: 'red', stroke: 'white', 'stroke-width': '1', visibility: 'hidden' - }; + } const elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '0', y: '1', width: '5', height: '10' } - }); - svgroot.append(elem); - const path = convertToPath(elem, attrs, mockaddSVGElemensFromJson, mockPathActions, mockClearSelection, mockAddToSelection, mockHistory, mockAddCommandToHistory); - assert.equal(path.getAttribute('d'), 'M0,1 L5,1 L5,11 L0,11 L0,1 Z'); - assert.equal(path.getAttribute('visibilituy'), null); - assert.equal(path.id, 'rect'); - assert.equal(path.parentNode, svgroot); - assert.equal(elem.parentNode, null); - assert.equal(mockHistorySubCommands.length, 2); - assert.equal(mockCount.clearSelection, 1); - assert.equal(mockCount.addToSelection, 1); - assert.equal(mockCount.addCommandToHistory, 1); - path.remove(); - }); + }) + svgroot.append(elem) + const path = convertToPath(elem, attrs, mockaddSVGElemensFromJson, mockPathActions, mockClearSelection, mockAddToSelection, mockHistory, mockAddCommandToHistory) + assert.equal(path.getAttribute('d'), 'M0,1 L5,1 L5,11 L0,11 L0,1 Z') + assert.equal(path.getAttribute('visibilituy'), null) + assert.equal(path.id, 'rect') + assert.equal(path.parentNode, svgroot) + assert.equal(elem.parentNode, null) + assert.equal(mockHistorySubCommands.length, 2) + assert.equal(mockCount.clearSelection, 1) + assert.equal(mockCount.addToSelection, 1) + assert.equal(mockCount.addCommandToHistory, 1) + path.remove() + }) it('Test convertToPath unknown element', function () { - const { convertToPath } = utilities; + const { convertToPath } = utilities const attrs = { fill: 'red', stroke: 'white', 'stroke-width': '1', visibility: 'hidden' - }; + } const elem = { tagName: 'something unknown', id: 'something-unknown', - getAttribute () { return ''; }, + getAttribute () { return '' }, parentNode: svgroot - }; - const path = convertToPath(elem, attrs, mockaddSVGElemensFromJson, mockPathActions, mockClearSelection, mockAddToSelection, mockHistory, mockAddCommandToHistory); - assert.equal(path, null); - assert.equal(elem.parentNode, svgroot); - assert.equal(mockHistorySubCommands.length, 0); - assert.equal(mockCount.clearSelection, 0); - assert.equal(mockCount.addToSelection, 0); - assert.equal(mockCount.addCommandToHistory, 0); - }); -}); + } + const path = convertToPath(elem, attrs, mockaddSVGElemensFromJson, mockPathActions, mockClearSelection, mockAddToSelection, mockHistory, mockAddCommandToHistory) + assert.equal(path, null) + assert.equal(elem.parentNode, svgroot) + assert.equal(mockHistorySubCommands.length, 0) + assert.equal(mockCount.clearSelection, 0) + assert.equal(mockCount.addToSelection, 0) + assert.equal(mockCount.addCommandToHistory, 0) + }) +}) diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js index b0a4e8cc..e4ddb633 100644 --- a/cypress/plugins/index.js +++ b/cypress/plugins/index.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' // *********************************************************** // This example plugins/index.js can be used to load plugins @@ -11,6 +11,6 @@ // *********************************************************** require('@babel/register')({ - plugins: [ '@babel/plugin-transform-modules-commonjs' ] -}); -module.exports = require('./main.js').default; + plugins: ['@babel/plugin-transform-modules-commonjs'] +}) +module.exports = require('./main.js').default diff --git a/cypress/plugins/main.js b/cypress/plugins/main.js index 33100766..e2a29a7e 100644 --- a/cypress/plugins/main.js +++ b/cypress/plugins/main.js @@ -1,8 +1,8 @@ // This function is called when a project is opened or re-opened (e.g. due to // the project's config changing) -import codeCoverageTask from "@cypress/code-coverage/task.js"; -import { initPlugin } from "cypress-plugin-snapshots/plugin.js"; +import codeCoverageTask from '@cypress/code-coverage/task.js' +import { initPlugin } from 'cypress-plugin-snapshots/plugin.js' export default (on, config) => { // `on` is used to hook into various events Cypress emits @@ -12,35 +12,35 @@ export default (on, config) => { // `config` is the resolved Cypress config // https://docs.cypress.io/guides/tooling/code-coverage.html#Install-the-plugin - codeCoverageTask(on, config); - initPlugin(on, config); - on("before:browser:launch", (browser, launchOptions) => { - if (browser.name === "chrome" && browser.isHeadless) { + codeCoverageTask(on, config) + initPlugin(on, config) + on('before:browser:launch', (browser, launchOptions) => { + if (browser.name === 'chrome' && browser.isHeadless) { // fullPage screenshot size is 1400x1200 on non-retina screens // and 2800x2400 on retina screens - launchOptions.args.push("--window-size=1400,1200"); + launchOptions.args.push('--window-size=1400,1200') // force screen to be non-retina (1400x1200 size) - launchOptions.args.push("--force-device-scale-factor=1"); + launchOptions.args.push('--force-device-scale-factor=1') // force screen to be retina (2800x2400 size) // launchOptions.args.push('--force-device-scale-factor=2') } - if (browser.name === "electron" && browser.isHeadless) { + if (browser.name === 'electron' && browser.isHeadless) { // fullPage screenshot size is 1400x1200 - launchOptions.preferences.width = 1400; - launchOptions.preferences.height = 1200; + launchOptions.preferences.width = 1400 + launchOptions.preferences.height = 1200 } - if (browser.name === "firefox" && browser.isHeadless) { + if (browser.name === 'firefox' && browser.isHeadless) { // menubars take up height on the screen // so fullPage screenshot size is 1400x1126 - launchOptions.args.push("--width=1400"); - launchOptions.args.push("--height=1200"); + launchOptions.args.push('--width=1400') + launchOptions.args.push('--height=1200') } - return launchOptions; - }); - return config; -}; + return launchOptions + }) + return config +} diff --git a/cypress/support/assert-almostEquals.js b/cypress/support/assert-almostEquals.js index b2b42c73..bc828110 100644 --- a/cypress/support/assert-almostEquals.js +++ b/cypress/support/assert-almostEquals.js @@ -1,6 +1,6 @@ -import assertionWrapper from './assertion-wrapper.js'; +import assertionWrapper from './assertion-wrapper.js' -const NEAR_ZERO = 5e-6; // 0.000005, Firefox fails at higher levels of precision. +const NEAR_ZERO = 5e-6 // 0.000005, Firefox fails at higher levels of precision. /** * Checks that the supplied values are equal with a high though not absolute degree of precision. @@ -10,9 +10,9 @@ const NEAR_ZERO = 5e-6; // 0.000005, Firefox fails at higher levels of precision * @returns {void} */ function almostEquals (actual, expected, message) { - message = message || (actual + ' did not equal ' + expected); - const result = Math.abs(actual - expected) < NEAR_ZERO; - return { result, message, actual, expected }; + message = message || (actual + ' did not equal ' + expected) + const result = Math.abs(actual - expected) < NEAR_ZERO + return { result, message, actual, expected } } /** @@ -21,9 +21,9 @@ function almostEquals (actual, expected, message) { * @returns {void} */ function setAssertionMethods (_chai, utils) { - const wrap = assertionWrapper(_chai, utils); + const wrap = assertionWrapper(_chai, utils) - assert.almostEquals = wrap(almostEquals); + assert.almostEquals = wrap(almostEquals) } -export default setAssertionMethods; +export default setAssertionMethods diff --git a/cypress/support/assert-close.js b/cypress/support/assert-close.js index 4f617bbb..e18b4cd1 100644 --- a/cypress/support/assert-close.js +++ b/cypress/support/assert-close.js @@ -1,4 +1,4 @@ -import assertionWrapper from './assertion-wrapper.js'; +import assertionWrapper from './assertion-wrapper.js' /** * @typedef {PlainObject} InfoObject @@ -21,10 +21,10 @@ import assertionWrapper from './assertion-wrapper.js'; * @returns {InfoObject} */ function close (actual, expected, maxDifference, message) { - const actualDiff = (actual === expected) ? 0 : Math.abs(actual - expected); - const result = actualDiff <= maxDifference; - message = message || (actual + ' should be within ' + maxDifference + ' (inclusive) of ' + expected + (result ? '' : '. Actual: ' + actualDiff)); - return { result, message, actual, expected }; + const actualDiff = (actual === expected) ? 0 : Math.abs(actual - expected) + const result = actualDiff <= maxDifference + message = message || (actual + ' should be within ' + maxDifference + ' (inclusive) of ' + expected + (result ? '' : '. Actual: ' + actualDiff)) + return { result, message, actual, expected } } /** @@ -40,21 +40,21 @@ function close (actual, expected, maxDifference, message) { * @returns {InfoObject} */ function closePercent (actual, expected, maxPercentDifference, message) { - let actualDiff; let result; + let actualDiff; let result if (actual === expected) { - actualDiff = 0; - result = actualDiff <= maxPercentDifference; + actualDiff = 0 + result = actualDiff <= maxPercentDifference } else if (actual !== 0 && expected !== 0 && expected !== Infinity && expected !== -Infinity) { - actualDiff = Math.abs(100 * (actual - expected) / expected); - result = actualDiff <= maxPercentDifference; + actualDiff = Math.abs(100 * (actual - expected) / expected) + result = actualDiff <= maxPercentDifference } else { // Dividing by zero (0)! Should return `false` unless the max percentage was `Infinity` - actualDiff = Infinity; - result = maxPercentDifference === Infinity; + actualDiff = Infinity + result = maxPercentDifference === Infinity } - message = message || (actual + ' should be within ' + maxPercentDifference + '% (inclusive) of ' + expected + (result ? '' : '. Actual: ' + actualDiff + '%')); + message = message || (actual + ' should be within ' + maxPercentDifference + '% (inclusive) of ' + expected + (result ? '' : '. Actual: ' + actualDiff + '%')) - return { result, message, actual, expected }; + return { result, message, actual, expected } } /** @@ -70,10 +70,10 @@ function closePercent (actual, expected, maxPercentDifference, message) { * @returns {InfoObject} */ function notClose (actual, expected, minDifference, message) { - const actualDiff = Math.abs(actual - expected); - const result = actualDiff > minDifference; - message = message || (actual + ' should not be within ' + minDifference + ' (exclusive) of ' + expected + (result ? '' : '. Actual: ' + actualDiff)); - return { result, message, actual, expected }; + const actualDiff = Math.abs(actual - expected) + const result = actualDiff > minDifference + message = message || (actual + ' should not be within ' + minDifference + ' (exclusive) of ' + expected + (result ? '' : '. Actual: ' + actualDiff)) + return { result, message, actual, expected } } /** @@ -89,21 +89,21 @@ function notClose (actual, expected, minDifference, message) { * @returns {InfoObject} */ function notClosePercent (actual, expected, minPercentDifference, message) { - let actualDiff; let result; + let actualDiff; let result if (actual === expected) { - actualDiff = 0; - result = actualDiff > minPercentDifference; + actualDiff = 0 + result = actualDiff > minPercentDifference } else if (actual !== 0 && expected !== 0 && expected !== Infinity && expected !== -Infinity) { - actualDiff = Math.abs(100 * (actual - expected) / expected); - result = actualDiff > minPercentDifference; + actualDiff = Math.abs(100 * (actual - expected) / expected) + result = actualDiff > minPercentDifference } else { // Dividing by zero (0)! Should only return `true` if the min percentage was `Infinity` - actualDiff = Infinity; - result = minPercentDifference !== Infinity; + actualDiff = Infinity + result = minPercentDifference !== Infinity } - message = message || (actual + ' should not be within ' + minPercentDifference + '% (exclusive) of ' + expected + (result ? '' : '. Actual: ' + actualDiff + '%')); + message = message || (actual + ' should not be within ' + minPercentDifference + '% (exclusive) of ' + expected + (result ? '' : '. Actual: ' + actualDiff + '%')) - return { result, message, actual, expected }; + return { result, message, actual, expected } } /** @@ -112,12 +112,12 @@ function notClosePercent (actual, expected, minPercentDifference, message) { * @returns {void} */ function setAssertionMethods (_chai, utils) { - const wrap = assertionWrapper(_chai, utils); + const wrap = assertionWrapper(_chai, utils) - assert.close = wrap(close); - assert.closePercent = wrap(closePercent); - assert.notClose = wrap(notClose); - assert.notClosePercent = wrap(notClosePercent); + assert.close = wrap(close) + assert.closePercent = wrap(closePercent) + assert.notClose = wrap(notClose) + assert.notClosePercent = wrap(notClosePercent) } -export default setAssertionMethods; +export default setAssertionMethods diff --git a/cypress/support/assert-expectOutOfBoundsException.js b/cypress/support/assert-expectOutOfBoundsException.js index de884e1f..8a3242e2 100644 --- a/cypress/support/assert-expectOutOfBoundsException.js +++ b/cypress/support/assert-expectOutOfBoundsException.js @@ -1,4 +1,4 @@ -import assertionWrapper from './assertion-wrapper.js'; +import assertionWrapper from './assertion-wrapper.js' /** * Expects an out of bounds `INDEX_SIZE_ERR` exception. @@ -8,18 +8,18 @@ import assertionWrapper from './assertion-wrapper.js'; * @returns {void} */ function expectOutOfBoundsException (obj, fn, arg1) { - const expected = true; - const message = 'Caught an INDEX_SIZE_ERR exception'; - let result = false; + const expected = true + const message = 'Caught an INDEX_SIZE_ERR exception' + let result = false try { - obj[fn](arg1); + obj[fn](arg1) } catch (e) { if (e.code === 1) { - result = true; + result = true } } - const actual = result; - return { result, message, actual, expected }; + const actual = result + return { result, message, actual, expected } } /** @@ -28,9 +28,9 @@ function expectOutOfBoundsException (obj, fn, arg1) { * @returns {void} */ function setAssertionMethods (_chai, utils) { - const wrap = assertionWrapper(_chai, utils); + const wrap = assertionWrapper(_chai, utils) - assert.expectOutOfBoundsException = wrap(expectOutOfBoundsException); + assert.expectOutOfBoundsException = wrap(expectOutOfBoundsException) } -export default setAssertionMethods; +export default setAssertionMethods diff --git a/cypress/support/assertion-wrapper.js b/cypress/support/assertion-wrapper.js index 65a02776..e38905fc 100644 --- a/cypress/support/assertion-wrapper.js +++ b/cypress/support/assertion-wrapper.js @@ -6,10 +6,10 @@ function setAssertionMethods (_chai, _utils) { return (method) => { return (...args) => { - const { result, message, actual, expected } = method(...args); - const assertion = new _chai.Assertion(); - assertion.assert(result, `Expected ${actual} to be ${expected}`, message); - }; - }; + const { result, message, actual, expected } = method(...args) + const assertion = new _chai.Assertion() + assertion.assert(result, `Expected ${actual} to be ${expected}`, message) + } + } } -export default setAssertionMethods; +export default setAssertionMethods diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 2384dcbf..33de4769 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -23,9 +23,9 @@ // // -- This will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) - +/* globals Cypress */ // remove the style attributes that is causing differences in snapshots -const ngAttributes = [ 'style' ]; +const ngAttributes = ['style'] Cypress.Commands.add( 'cleanSnapshot', @@ -33,16 +33,16 @@ Cypress.Commands.add( prevSubject: true }, (subject, _snapshotOptions) => { - let html = subject[0].outerHTML; + let html = subject[0].outerHTML for (const attribute of ngAttributes) { - const expression = new RegExp(`${attribute}[^= ]*="[^"]*"`, 'g'); - html = html.replace(expression, ''); + const expression = new RegExp(`${attribute}[^= ]*="[^"]*"`, 'g') + html = html.replace(expression, '') } - html = html.replace(//g, ''); + html = html.replace(//g, '') - const sanitisedBody = new DOMParser().parseFromString(html, 'text/html').querySelector('body'); + const sanitisedBody = new DOMParser().parseFromString(html, 'text/html').querySelector('body') - return cy.wrap(sanitisedBody.firstChild).toMatchSnapshot(); + return cy.wrap(sanitisedBody.firstChild).toMatchSnapshot() } -); +) diff --git a/cypress/support/index.js b/cypress/support/index.js index 27fcdbe3..f4f9cc0c 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -14,7 +14,7 @@ // *********************************************************** // Import commands.js using ES2015 syntax: -import './commands.js'; +import './commands.js' // Alternatively you can use CommonJS syntax: // require('./commands') @@ -29,17 +29,17 @@ import './commands.js'; * @see https://github.com/cypress-io/cypress-fiddle * @example import {testExamples} from '@cypress/fiddle'; */ -import '@cypress/fiddle'; +import '@cypress/fiddle' /** * COVERAGE. * @see https://docs.cypress.io/guides/tooling/code-coverage.html#Install-the-plugin */ -import '@cypress/code-coverage/support.js'; +import '@cypress/code-coverage/support.js' /***** * SNAPSHOTS * @see https://www.npmjs.com/package/cypress-plugin-snapshots */ -import 'cypress-plugin-snapshots/commands.js'; +import 'cypress-plugin-snapshots/commands.js' diff --git a/cypress/support/ui-test-helper.js b/cypress/support/ui-test-helper.js index 80ca022f..1276cebd 100644 --- a/cypress/support/ui-test-helper.js +++ b/cypress/support/ui-test-helper.js @@ -1,24 +1,24 @@ export const approveStorage = () => { // JFH will need to be chnaged when dialog is changed... - cy.get('#storage_ok').click(); -}; + cy.get('#storage_ok').click() +} export const visitAndApproveStorage = () => { - cy.visit('/instrumented/editor/index.html'); - approveStorage(); -}; + cy.visit('/instrumented/editor/index.html') + approveStorage() +} export const openMainMenu = () => { - return cy.get('#main_button').click({ force: true }); -}; + return cy.get('#main_button').click({ force: true }) +} export const openEditorPreferences = () => { - openMainMenu(); - return cy.get('#tool_editor_prefs').click(); -}; + openMainMenu() + return cy.get('#tool_editor_prefs').click() +} export const selectEnglish = () => { - openEditorPreferences(); - cy.get('#lang_select').select('en'); - cy.get('#tool_prefs_save').click(); -}; + openEditorPreferences() + cy.get('#lang_select').select('en') + cy.get('#tool_prefs_save').click() +} diff --git a/demos/canvas.html b/demos/canvas.html index 0a903806..c98aee3d 100644 --- a/demos/canvas.html +++ b/demos/canvas.html @@ -27,14 +27,14 @@ diff --git a/docs/jsdoc-config.js b/docs/jsdoc-config.js index 348cb8f4..1cf78182 100644 --- a/docs/jsdoc-config.js +++ b/docs/jsdoc-config.js @@ -1,8 +1,8 @@ /* eslint-env node */ -'use strict'; +'use strict' module.exports = { - plugins: [ 'plugins/markdown' ], + plugins: ['plugins/markdown'], markdown: {}, recurseDepth: 10, source: { @@ -33,4 +33,4 @@ module.exports = { destination: 'docs/jsdoc', tutorials: 'docs/tutorials' } -}; +} diff --git a/docs/tutorials/ConfigOptions.md b/docs/tutorials/ConfigOptions.md index c57e367d..82ca71b4 100644 --- a/docs/tutorials/ConfigOptions.md +++ b/docs/tutorials/ConfigOptions.md @@ -48,7 +48,7 @@ svgEditor.setConfig({ initFill: { color: '0000FF' } -}); +}) ``` This will set the default width/height of the image, the size of the outside @@ -121,13 +121,13 @@ set if storage is found. ```js // Serialized string: -svgEditor.loadFromString('...'); +svgEditor.loadFromString('...') // Data URI: -svgEditor.loadFromDataURI('data:image/svg+xml;base64,...'); +svgEditor.loadFromDataURI('data:image/svg+xml;base64,...') // Local URL: -svgEditor.loadFromURL('images/logo.svg'); +svgEditor.loadFromURL('images/logo.svg') ``` ### Preload a file (by URL) @@ -136,13 +136,13 @@ As a URL parameter, one can pre-load an SVG file in the following manner: ```js // Data URI -location.href += '?source=' + encodeURIComponent('data:image/svg+xml;utf8,' + svgText); +location.href += '?source=' + encodeURIComponent('data:image/svg+xml;utf8,' + svgText) // Data URI (base 64): -location.href += '?source=' + encodeURIComponent('data:image/svg+xml;base64,' + svgTextAsBase64); // data%3Aimage%2Fsvg%2Bxml%3Bbase64%2C ... +location.href += '?source=' + encodeURIComponent('data:image/svg+xml;base64,' + svgTextAsBase64) // data%3Aimage%2Fsvg%2Bxml%3Bbase64%2C ... // Local URL: -location.href += '?url=' + encodeURIComponent('images/logo.svg'); // images%2Flogo.svg +location.href += '?url=' + encodeURIComponent('images/logo.svg') // images%2Flogo.svg ``` **Note:** There is currently a bug that prevents data URIs ending with @@ -160,7 +160,7 @@ To add your own stylesheets along with the default stylesheets, ensure `"@default"` is present in the array along with your own. For example: ```js -svgEditor.setConfig({ stylesheets: [ '@default', 'myStylesheet.css' ] }); +svgEditor.setConfig({ stylesheets: [ '@default', 'myStylesheet.css' ] }) ``` (In version 2.8, the CSS file `editor/custom.css` was included by default, diff --git a/docs/tutorials/Events.md b/docs/tutorials/Events.md index b0f3e42d..5b7327e0 100644 --- a/docs/tutorials/Events.md +++ b/docs/tutorials/Events.md @@ -11,7 +11,7 @@ svgEditor.setCustomHandlers({ save (_win, _data) { // Save svg } -}); +}) ``` Other methods corresponding to UI events that may be supplied are `open` @@ -40,9 +40,9 @@ $(document).bind('svgEditorReady', function () { "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> - `; - $('iframe.svgedit')[0].contentWindow.svgCanvas.setSvgString(svg); -}); + ` + $('iframe.svgedit')[0].contentWindow.svgCanvas.setSvgString(svg) +}) ``` If you are acting within the frame, you may use `svgEditor.ready` @@ -86,7 +86,7 @@ Canvas events are listened to with the bind method ([JSDocs API]{@link module:svgcanvas.SvgCanvas#bind}): ```js -canvas.bind(eventName, callback); +canvas.bind(eventName, callback) ``` Canvas events are passed between the editor and canvas and should mostly diff --git a/docs/tutorials/ExtensionDocs.md b/docs/tutorials/ExtensionDocs.md index 9744d624..10b0c70d 100644 --- a/docs/tutorials/ExtensionDocs.md +++ b/docs/tutorials/ExtensionDocs.md @@ -28,9 +28,9 @@ This is the general format for an extension: export default { name: 'extensionname', init (_methods) { - return extensionData; + return extensionData } -}; +} ``` Extensions must export an object. (For the API docs of this object, see @@ -86,9 +86,9 @@ export default { mouseUp (_opts) { // ... } - }; + } } -}; +} ``` Note how the returned properties may include information on the buttons, @@ -145,15 +145,15 @@ import { importSetGlobalDefault } from '../external/dynamic-import-polyfill/impo (async () => { - const url = `${svgEditor.curConfig.extPath}ext-locale//.js`; + const url = `${svgEditor.curConfig.extPath}ext-locale//.js` const localeStrings = await importSetGlobalDefault(url, { global: 'svgEditorExtensionLocale_imagelib_' + lang - }); + }) // Use `localeStrings` - console.info(localeStrings); + console.info(localeStrings) -})(); +})() ``` In addition to your own extension's locale strings, diff --git a/docs/versions/3.0.0.md b/docs/versions/3.0.0.md index 8c7f58c0..8d39e514 100644 --- a/docs/versions/3.0.0.md +++ b/docs/versions/3.0.0.md @@ -120,7 +120,7 @@ these files). The default behavior is equivalent to this: ```js svgEditor.setConfig({ stylesheets: [ '@default', '../svgedit-custom.css' ] -}); +}) ``` ...which indicates that all default stylesheets will be loaded and then diff --git a/nyc.config.js b/nyc.config.js index 88e2f0c3..d29b8374 100644 --- a/nyc.config.js +++ b/nyc.config.js @@ -1,16 +1,16 @@ module.exports = { - "statements": 45, - "branches": 34, - "lines": 46, - "functions": 45, + statements: 45, + branches: 34, + lines: 46, + functions: 45, exclude: [ 'editor/jquery.min.js', 'editor/jgraduate/**' ], - "reporter": [ - "json-summary", - "text", - "html" + reporter: [ + 'json-summary', + 'text', + 'html' ] -}; +} diff --git a/package-lock.json b/package-lock.json index 1a123540..09246d67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,58 +12,38 @@ "@babel/polyfill": "7.12.1", "browser-fs-access": "0.23.0", "canvg": "3.0.9", - "core-js": "3.19.3", + "core-js": "3.20.1", "elix": "15.0.1", "html2canvas": "1.3.3", - "i18next": "21.6.0", - "jspdf": "2.4.0", + "i18next": "21.6.4", + "jspdf": "2.5.0", "pathseg": "1.2.1", "regenerator-runtime": "0.13.9", "rollup-plugin-polyfill-node": "0.8.0", "svg2pdf.js": "2.2.0" }, "devDependencies": { - "@babel/core": "7.16.0", - "@babel/preset-env": "7.16.4", - "@babel/register": "7.16.0", - "@babel/runtime-corejs3": "7.16.3", + "@babel/core": "7.16.5", + "@babel/preset-env": "7.16.5", + "@babel/register": "7.16.5", + "@babel/runtime-corejs3": "7.16.5", "@cypress/code-coverage": "3.9.12", "@cypress/fiddle": "1.19.3", - "@fintechstudios/eslint-plugin-chai-as-promised": "3.1.0", "@rollup/plugin-babel": "5.3.0", "@rollup/plugin-commonjs": "^18", "@rollup/plugin-dynamic-import-vars": "1.4.1", - "@rollup/plugin-node-resolve": "13.0.6", + "@rollup/plugin-node-resolve": "13.1.1", "@rollup/plugin-replace": "3.0.0", "@rollup/plugin-url": "6.1.0", "@web/dev-server": "0.1.28", - "@web/dev-server-esbuild": "^0.2.16", "@web/dev-server-rollup": "0.3.13", "babel-plugin-transform-object-rest-spread": "7.0.0-beta.3", "copyfiles": "2.4.1", - "core-js-bundle": "3.19.3", + "core-js-bundle": "3.20.1", "cp-cli": "2.0.0", - "cypress": "9.1.1", + "cypress": "9.2.0", "cypress-multi-reporters": "1.5.0", "cypress-plugin-snapshots": "1.4.4", - "eslint": "^7", - "eslint-config-standard": "16.0.3", - "eslint-plugin-array-func": "3.1.7", - "eslint-plugin-chai-expect": "3.0.0", - "eslint-plugin-chai-expect-keywords": "2.1.0", - "eslint-plugin-chai-friendly": "0.7.2", - "eslint-plugin-compat": "4.0.0", - "eslint-plugin-cypress": "2.12.1", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-html": "6.2.0", - "eslint-plugin-import": "2.25.3", - "eslint-plugin-jsdoc": "37.2.0", - "eslint-plugin-markdown": "2.2.1", - "eslint-plugin-no-unsanitized": "4.0.1", - "eslint-plugin-no-use-extend-native": "0.5.0", - "eslint-plugin-node": "11.1.0", - "eslint-plugin-promise": "5.2.0", - "eslint-plugin-standard": "4.1.0", "jamilih": "0.54.0", "jsdoc": "3.6.7", "node-static": "0.7.11", @@ -76,7 +56,7 @@ "remark-cli": "10.0.1", "remark-lint-ordered-list-marker-value": "3.1.1", "rimraf": "3.0.2", - "rollup": "2.61.0", + "rollup": "2.62.0", "rollup-plugin-copy": "3.4.0", "rollup-plugin-filesize": "9.1.1", "rollup-plugin-html": "^0.2.1", @@ -84,6 +64,7 @@ "rollup-plugin-progress": "1.1.2", "rollup-plugin-re": "1.0.7", "rollup-plugin-terser": "7.0.2", + "standard": "16.0.4", "start-server-and-test": "1.14.0" }, "engines": { @@ -112,19 +93,19 @@ } }, "node_modules/@babel/core": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.0.tgz", - "integrity": "sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.5.tgz", + "integrity": "sha512-wUcenlLzuWMZ9Zt8S0KmFwGlH6QKRh3vsm/dhDA3CHkiTA45YuG1XkHRcNRl73EFPXDp/d5kVOU0/y7x2w6OaQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.0", - "@babel/helper-compilation-targets": "^7.16.0", - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helpers": "^7.16.0", - "@babel/parser": "^7.16.0", + "@babel/generator": "^7.16.5", + "@babel/helper-compilation-targets": "^7.16.3", + "@babel/helper-module-transforms": "^7.16.5", + "@babel/helpers": "^7.16.5", + "@babel/parser": "^7.16.5", "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", + "@babel/traverse": "^7.16.5", "@babel/types": "^7.16.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", @@ -169,9 +150,9 @@ } }, "node_modules/@babel/generator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.0.tgz", - "integrity": "sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.5.tgz", + "integrity": "sha512-kIvCdjZqcdKqoDbVVdt5R99icaRtrtYhYK/xux5qiWCBmfdvEYMFZ68QCrpE5cbFM1JsuArUNs1ZkuKtTtUcZA==", "dev": true, "dependencies": { "@babel/types": "^7.16.0", @@ -195,9 +176,9 @@ } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.0.tgz", - "integrity": "sha512-9KuleLT0e77wFUku6TUkqZzCEymBdtuQQ27MhEKzf9UOOJu3cYj98kyaDAzxpC7lV6DGiZFuC8XqDsq8/Kl6aQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.5.tgz", + "integrity": "sha512-3JEA9G5dmmnIWdzaT9d0NmFRgYnWUThLsDaL7982H0XqqWr56lRrsmwheXFMjR+TMl7QMBb6mzy9kvgr1lRLUA==", "dev": true, "dependencies": { "@babel/helper-explode-assignable-expression": "^7.16.0", @@ -235,16 +216,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz", - "integrity": "sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.5.tgz", + "integrity": "sha512-NEohnYA7mkB8L5JhU7BLwcBdU3j83IziR9aseMueWGeAjblbul3zzb8UvJ3a1zuBiqCMObzCJHFqKIQE6hTVmg==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.0", + "@babel/helper-environment-visitor": "^7.16.5", "@babel/helper-function-name": "^7.16.0", - "@babel/helper-member-expression-to-functions": "^7.16.0", + "@babel/helper-member-expression-to-functions": "^7.16.5", "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/helper-replace-supers": "^7.16.0", + "@babel/helper-replace-supers": "^7.16.5", "@babel/helper-split-export-declaration": "^7.16.0" }, "engines": { @@ -321,6 +303,18 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz", + "integrity": "sha512-ODQyc5AnxmZWm/R2W7fzhamOk1ey8gSguo5SGvF0zcB3uUzRpTRmM/jmLSm9bDMyPlvbyJ+PwPEK0BWIoZ9wjg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-explode-assignable-expression": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz", @@ -372,9 +366,9 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz", - "integrity": "sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.5.tgz", + "integrity": "sha512-7fecSXq7ZrLE+TWshbGT+HyCLkxloWNhTbU2QM1NTI/tDqyf0oZiMcEfYtDuUDCo528EOlt39G1rftea4bRZIw==", "dev": true, "dependencies": { "@babel/types": "^7.16.0" @@ -396,18 +390,18 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz", - "integrity": "sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.5.tgz", + "integrity": "sha512-CkvMxgV4ZyyioElFwcuWnDCcNIeyqTkCm9BxXZi73RR1ozqlpboqsbGUNvRTflgZtFbbJ1v5Emvm+lkjMYY/LQ==", "dev": true, "dependencies": { + "@babel/helper-environment-visitor": "^7.16.5", "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-replace-supers": "^7.16.0", "@babel/helper-simple-access": "^7.16.0", "@babel/helper-split-export-declaration": "^7.16.0", "@babel/helper-validator-identifier": "^7.15.7", "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", + "@babel/traverse": "^7.16.5", "@babel/types": "^7.16.0" }, "engines": { @@ -427,22 +421,22 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz", + "integrity": "sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.4.tgz", - "integrity": "sha512-vGERmmhR+s7eH5Y/cp8PCVzj4XEjerq8jooMfxFdA5xVtAk9Sh4AQsrWgiErUEBjtGrBtOFKDUcWQFW4/dFwMA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.5.tgz", + "integrity": "sha512-X+aAJldyxrOmN9v3FKp+Hu1NO69VWgYgDGq6YDykwRPzxs5f2N+X988CBXS7EQahDU+Vpet5QYMqLk+nsp+Qxw==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-wrap-function": "^7.16.0", + "@babel/helper-wrap-function": "^7.16.5", "@babel/types": "^7.16.0" }, "engines": { @@ -450,14 +444,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz", - "integrity": "sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.5.tgz", + "integrity": "sha512-ao3seGVa/FZCMCCNDuBcqnBFSbdr8N2EW35mzojx3TwfIbdPmNK+JV6+2d5bR0Z71W5ocLnQp9en/cTF7pBJiQ==", "dev": true, "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.16.0", + "@babel/helper-environment-visitor": "^7.16.5", + "@babel/helper-member-expression-to-functions": "^7.16.5", "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/traverse": "^7.16.0", + "@babel/traverse": "^7.16.5", "@babel/types": "^7.16.0" }, "engines": { @@ -519,14 +514,14 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz", - "integrity": "sha512-VVMGzYY3vkWgCJML+qVLvGIam902mJW0FvT7Avj1zEe0Gn7D93aWdLblYARTxEw+6DhZmtzhBM2zv0ekE5zg1g==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.5.tgz", + "integrity": "sha512-2J2pmLBqUqVdJw78U0KPNdeE2qeuIyKoG4mKV7wAq3mc4jJG282UgjZw4ZYDnqiWQuS3Y3IYdF/AQ6CpyBV3VA==", "dev": true, "dependencies": { "@babel/helper-function-name": "^7.16.0", "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", + "@babel/traverse": "^7.16.5", "@babel/types": "^7.16.0" }, "engines": { @@ -534,13 +529,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.16.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.3.tgz", - "integrity": "sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.5.tgz", + "integrity": "sha512-TLgi6Lh71vvMZGEkFuIxzaPsyeYCHQ5jJOOX1f0xXn0uciFuE8cEk0wyBquMcCxBXZ5BJhE2aUB7pnWTD150Tw==", "dev": true, "dependencies": { "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.3", + "@babel/traverse": "^7.16.5", "@babel/types": "^7.16.0" }, "engines": { @@ -562,9 +557,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.4.tgz", - "integrity": "sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng==", + "version": "7.16.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.6.tgz", + "integrity": "sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -606,13 +601,13 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.4.tgz", - "integrity": "sha512-/CUekqaAaZCQHleSK/9HajvcD/zdnJiKRiuUFq8ITE+0HsPzquf53cpFiqAwl/UfmJbR6n5uGPQSPdrmKOvHHg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.5.tgz", + "integrity": "sha512-C/FX+3HNLV6sz7AqbTQqEo1L9/kfrKjxcVtgyBCmvIgOjvuBVUWooDoi7trsLxOzCEo5FccjRvKHkfDsJFZlfA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.16.4", + "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-remap-async-to-generator": "^7.16.5", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -623,13 +618,13 @@ } }, "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz", - "integrity": "sha512-mCF3HcuZSY9Fcx56Lbn+CGdT44ioBMMvjNVldpKtj8tpniETdLjnxdHI1+sDWXIM1nNt+EanJOZ3IG9lzVjs7A==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.5.tgz", + "integrity": "sha512-pJD3HjgRv83s5dv1sTnDbZOaTjghKEz8KUn1Kbh2eAIRhGuyQ1XSeI4xVXU3UlIEVA3DAyIdxqT1eRn7Wcn55A==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -639,13 +634,13 @@ } }, "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.0.tgz", - "integrity": "sha512-mAy3sdcY9sKAkf3lQbDiv3olOfiLqI51c9DR9b19uMoR2Z6r5pmGl7dfNFqEvqOyqbf1ta4lknK4gc5PJn3mfA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.5.tgz", + "integrity": "sha512-EEFzuLZcm/rNJ8Q5krK+FRKdVkd6FjfzT9tuSZql9sQn64K0hHA2KLJ0DqVot9/iV6+SsuadC5yI39zWnm+nmQ==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-create-class-features-plugin": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -656,12 +651,12 @@ } }, "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz", - "integrity": "sha512-QGSA6ExWk95jFQgwz5GQ2Dr95cf7eI7TKutIXXTb7B1gCLTCz5hTjFTQGfLFBBiC5WSNi7udNwWsqbbMh1c4yQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.5.tgz", + "integrity": "sha512-P05/SJZTTvHz79LNYTF8ff5xXge0kk5sIIWAypcWgX4BTRUgyHc8wRxJ/Hk+mU0KXldgOOslKaeqnhthcDJCJQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { @@ -672,12 +667,12 @@ } }, "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz", - "integrity": "sha512-CjI4nxM/D+5wCnhD11MHB1AwRSAYeDT+h8gCdcVJZ/OK7+wRzFsf7PFPWVpVpNRkHMmMkQWAHpTq+15IXQ1diA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.5.tgz", + "integrity": "sha512-i+sltzEShH1vsVydvNaTRsgvq2vZsfyrd7K7vPLUU/KgS0D5yZMe6uipM0+izminnkKrEfdUnz7CxMRb6oHZWw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -688,12 +683,12 @@ } }, "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz", - "integrity": "sha512-kouIPuiv8mSi5JkEhzApg5Gn6hFyKPnlkO0a9YSzqRurH8wYzSlf6RJdzluAsbqecdW5pBvDJDfyDIUR/vLxvg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.5.tgz", + "integrity": "sha512-QQJueTFa0y9E4qHANqIvMsuxM/qcLQmKttBACtPCQzGUEizsXDACGonlPiSwynHfOa3vNw0FPMVvQzbuXwh4SQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -704,12 +699,12 @@ } }, "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz", - "integrity": "sha512-pbW0fE30sVTYXXm9lpVQQ/Vc+iTeQKiXlaNRZPPN2A2VdlWyAtsUrsQ3xydSlDW00TFMK7a8m3cDTkBF5WnV3Q==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.5.tgz", + "integrity": "sha512-xqibl7ISO2vjuQM+MzR3rkd0zfNWltk7n9QhaD8ghMmMceVguYrNDt7MikRyj4J4v3QehpnrU8RYLnC7z/gZLA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -720,12 +715,12 @@ } }, "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz", - "integrity": "sha512-3bnHA8CAFm7cG93v8loghDYyQ8r97Qydf63BeYiGgYbjKKB/XP53W15wfRC7dvKfoiJ34f6Rbyyx2btExc8XsQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.5.tgz", + "integrity": "sha512-YwMsTp/oOviSBhrjwi0vzCUycseCYwoXnLiXIL3YNjHSMBHicGTz7GjVU/IGgz4DtOEXBdCNG72pvCX22ehfqg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -736,12 +731,12 @@ } }, "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz", - "integrity": "sha512-FAhE2I6mjispy+vwwd6xWPyEx3NYFS13pikDBWUAFGZvq6POGs5eNchw8+1CYoEgBl9n11I3NkzD7ghn25PQ9Q==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.5.tgz", + "integrity": "sha512-DvB9l/TcsCRvsIV9v4jxR/jVP45cslTVC0PMVHvaJhhNuhn2Y1SOhCSFlPK777qLB5wb8rVDaNoqMTyOqtY5Iw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -752,16 +747,16 @@ } }, "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz", - "integrity": "sha512-LU/+jp89efe5HuWJLmMmFG0+xbz+I2rSI7iLc1AlaeSMDMOGzWlc5yJrMN1d04osXN4sSfpo4O+azkBNBes0jg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.5.tgz", + "integrity": "sha512-UEd6KpChoyPhCoE840KRHOlGhEZFutdPDMGj+0I56yuTTOaT51GzmnEl/0uT41fB/vD2nT+Pci2KjezyE3HmUw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.16.0", - "@babel/helper-compilation-targets": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/compat-data": "^7.16.4", + "@babel/helper-compilation-targets": "^7.16.3", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.0" + "@babel/plugin-transform-parameters": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -771,12 +766,12 @@ } }, "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz", - "integrity": "sha512-kicDo0A/5J0nrsCPbn89mTG3Bm4XgYi0CZtvex9Oyw7gGZE3HXGD0zpQNH+mo+tEfbo8wbmMvJftOwpmPy7aVw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.5.tgz", + "integrity": "sha512-ihCMxY1Iljmx4bWy/PIMJGXN4NS4oUj1MKynwO07kiKms23pNvIn1DMB92DNB2R0EA882sw0VXIelYGdtF7xEQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -787,12 +782,12 @@ } }, "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz", - "integrity": "sha512-Y4rFpkZODfHrVo70Uaj6cC1JJOt3Pp0MdWSwIKtb8z1/lsjl9AmnB7ErRFV+QNGIfcY1Eruc2UMx5KaRnXjMyg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.5.tgz", + "integrity": "sha512-kzdHgnaXRonttiTfKYnSVafbWngPPr2qKw9BWYBESl91W54e+9R5pP70LtWxV56g0f05f/SQrwHYkfvbwcdQ/A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, @@ -804,13 +799,13 @@ } }, "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz", - "integrity": "sha512-IvHmcTHDFztQGnn6aWq4t12QaBXTKr1whF/dgp9kz84X6GUcwq9utj7z2wFCUfeOup/QKnOlt2k0zxkGFx9ubg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.5.tgz", + "integrity": "sha512-+yFMO4BGT3sgzXo+lrq7orX5mAZt57DwUK6seqII6AcJnJOIhBJ8pzKH47/ql/d426uQ7YhN8DpUFirQzqYSUA==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -820,14 +815,14 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.0.tgz", - "integrity": "sha512-3jQUr/HBbMVZmi72LpjQwlZ55i1queL8KcDTQEkAHihttJnAPrcvG9ZNXIfsd2ugpizZo595egYV6xy+pv4Ofw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.5.tgz", + "integrity": "sha512-+YGh5Wbw0NH3y/E5YMu6ci5qTDmAEVNoZ3I54aB6nVEOZ5BQ7QJlwKq5pYVucQilMByGn/bvX0af+uNaPRCabA==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-create-class-features-plugin": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -838,13 +833,13 @@ } }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz", - "integrity": "sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.5.tgz", + "integrity": "sha512-s5sKtlKQyFSatt781HQwv1hoM5BQ9qRH30r+dK56OLDsHmV74mzwJNX7R1yMuE7VZKG5O6q/gmOGSAO6ikTudg==", "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=4" @@ -1031,12 +1026,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz", - "integrity": "sha512-vIFb5250Rbh7roWARvCLvIJ/PtAU5Lhv7BtZ1u24COwpI9Ypjsh+bZcKk6rlIyalK+r0jOc1XQ8I4ovNxNrWrA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.5.tgz", + "integrity": "sha512-8bTHiiZyMOyfZFULjsCnYOWG059FVMes0iljEHSfARhNgFfpsqE92OrCffv3veSw9rwMkYcFe9bj0ZoXU2IGtQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1046,14 +1041,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz", - "integrity": "sha512-PbIr7G9kR8tdH6g8Wouir5uVjklETk91GMVSUq+VaOgiinbCkBP6Q7NN/suM/QutZkMJMvcyAriogcYAdhg8Gw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.5.tgz", + "integrity": "sha512-TMXgfioJnkXU+XRoj7P2ED7rUm5jbnDWwlCuFVTpQboMfbSya5WrmubNBAMlk7KXvywpo8rd8WuYZkis1o2H8w==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.16.0" + "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-remap-async-to-generator": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1063,12 +1058,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz", - "integrity": "sha512-V14As3haUOP4ZWrLJ3VVx5rCnrYhMSHN/jX7z6FAt5hjRkLsb0snPCmJwSOML5oxkKO4FNoNv7V5hw/y2bjuvg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.5.tgz", + "integrity": "sha512-BxmIyKLjUGksJ99+hJyL/HIxLIGnLKtw772zYDER7UuycDZ+Xvzs98ZQw6NGgM2ss4/hlFAaGiZmMNKvValEjw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1078,12 +1073,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz", - "integrity": "sha512-27n3l67/R3UrXfizlvHGuTwsRIFyce3D/6a37GRxn28iyTPvNXaW4XvznexRh1zUNLPjbLL22Id0XQElV94ruw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.5.tgz", + "integrity": "sha512-JxjSPNZSiOtmxjX7PBRBeRJTUKTyJ607YUYeT0QJCNdsedOe+/rXITjP08eG8xUpsLfPirgzdCFN+h0w6RI+pQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1093,16 +1088,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz", - "integrity": "sha512-HUxMvy6GtAdd+GKBNYDWCIA776byUQH8zjnfjxwT1P1ARv/wFu8eBDpmXQcLS/IwRtrxIReGiplOwMeyO7nsDQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.5.tgz", + "integrity": "sha512-DzJ1vYf/7TaCYy57J3SJ9rV+JEuvmlnvvyvYKFbk5u46oQbBvuB9/0w+YsVsxkOv8zVWKpDmUoj4T5ILHoXevA==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.0", + "@babel/helper-environment-visitor": "^7.16.5", "@babel/helper-function-name": "^7.16.0", "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.16.0", + "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-replace-supers": "^7.16.5", "@babel/helper-split-export-declaration": "^7.16.0", "globals": "^11.1.0" }, @@ -1114,12 +1110,12 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz", - "integrity": "sha512-63l1dRXday6S8V3WFY5mXJwcRAnPYxvFfTlt67bwV1rTyVTM5zrp0DBBb13Kl7+ehkCVwIZPumPpFP/4u70+Tw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.5.tgz", + "integrity": "sha512-n1+O7xtU5lSLraRzX88CNcpl7vtGdPakKzww74bVwpAIRgz9JVLJJpOLb0uYqcOaXVM0TL6X0RVeIJGD2CnCkg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1129,12 +1125,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz", - "integrity": "sha512-Q7tBUwjxLTsHEoqktemHBMtb3NYwyJPTJdM+wDwb0g8PZ3kQUIzNvwD5lPaqW/p54TXBc/MXZu9Jr7tbUEUM8Q==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.5.tgz", + "integrity": "sha512-GuRVAsjq+c9YPK6NeTkRLWyQskDC099XkBSVO+6QzbnOnH2d/4mBVXYStaPrZD3dFRfg00I6BFJ9Atsjfs8mlg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1144,13 +1140,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz", - "integrity": "sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.5.tgz", + "integrity": "sha512-iQiEMt8Q4/5aRGHpGVK2Zc7a6mx7qEAO7qehgSug3SDImnuMzgmm/wtJALXaz25zUj1PmnNHtShjFgk4PDx4nw==", "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1160,12 +1156,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz", - "integrity": "sha512-LIe2kcHKAZOJDNxujvmp6z3mfN6V9lJxubU4fJIGoQCkKe3Ec2OcbdlYP+vW++4MpxwG0d1wSDOJtQW5kLnkZQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.5.tgz", + "integrity": "sha512-81tijpDg2a6I1Yhj4aWY1l3O1J4Cg/Pd7LfvuaH2VVInAkXtzibz9+zSPdUM1WvuUi128ksstAP0hM5w48vQgg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1175,13 +1171,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz", - "integrity": "sha512-OwYEvzFI38hXklsrbNivzpO3fh87skzx8Pnqi4LoSYeav0xHlueSoCJrSgTPfnbyzopo5b3YVAJkFIcUpK2wsw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.5.tgz", + "integrity": "sha512-12rba2HwemQPa7BLIKCzm1pT2/RuQHtSFHdNl41cFiC6oi4tcrp7gjB07pxQvFpcADojQywSjblQth6gJyE6CA==", "dev": true, "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1191,12 +1187,12 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz", - "integrity": "sha512-5QKUw2kO+GVmKr2wMYSATCTTnHyscl6sxFRAY+rvN7h7WB0lcG0o4NoV6ZQU32OZGVsYUsfLGgPQpDFdkfjlJQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.5.tgz", + "integrity": "sha512-+DpCAJFPAvViR17PIMi9x2AE34dll5wNlXO43wagAX2YcRGgEVHCNFC4azG85b4YyyFarvkc/iD5NPrz4Oneqw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1206,13 +1202,13 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz", - "integrity": "sha512-lBzMle9jcOXtSOXUpc7tvvTpENu/NuekNJVova5lCCWCV9/U1ho2HH2y0p6mBg8fPm/syEAbfaaemYGOHCY3mg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.5.tgz", + "integrity": "sha512-Fuec/KPSpVLbGo6z1RPw4EE1X+z9gZk1uQmnYy7v4xr4TO9p41v1AoUuXEtyqAI7H+xNJYSICzRqZBhDEkd3kQ==", "dev": true, "dependencies": { "@babel/helper-function-name": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1222,12 +1218,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz", - "integrity": "sha512-gQDlsSF1iv9RU04clgXqRjrPyyoJMTclFt3K1cjLmTKikc0s/6vE3hlDeEVC71wLTRu72Fq7650kABrdTc2wMQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.5.tgz", + "integrity": "sha512-B1j9C/IfvshnPcklsc93AVLTrNVa69iSqztylZH6qnmiAsDDOmmjEYqOm3Ts2lGSgTSywnBNiqC949VdD0/gfw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1237,12 +1233,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz", - "integrity": "sha512-WRpw5HL4Jhnxw8QARzRvwojp9MIE7Tdk3ez6vRyUk1MwgjJN0aNpRoXainLR5SgxmoXx/vsXGZ6OthP6t/RbUg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.5.tgz", + "integrity": "sha512-d57i3vPHWgIde/9Y8W/xSFUndhvhZN5Wu2TjRrN1MVz5KzdUihKnfDVlfP1U7mS5DNj/WHHhaE4/tTi4hIyHwQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1252,13 +1248,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz", - "integrity": "sha512-rWFhWbCJ9Wdmzln1NmSCqn7P0RAD+ogXG/bd9Kg5c7PKWkJtkiXmYsMBeXjDlzHpVTJ4I/hnjs45zX4dEv81xw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.5.tgz", + "integrity": "sha512-oHI15S/hdJuSCfnwIz+4lm6wu/wBn7oJ8+QrkzPPwSFGXk8kgdI/AIKcbR/XnD1nQVMg/i6eNaXpszbGuwYDRQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-module-transforms": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -1269,13 +1265,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz", - "integrity": "sha512-Dzi+NWqyEotgzk/sb7kgQPJQf7AJkQBWsVp1N6JWc1lBVo0vkElUnGdr1PzUBmfsCCN5OOFya3RtpeHk15oLKQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.5.tgz", + "integrity": "sha512-ABhUkxvoQyqhCWyb8xXtfwqNMJD7tx+irIRnUh6lmyFud7Jln1WzONXKlax1fg/ey178EXbs4bSGNd6PngO+SQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-module-transforms": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/helper-simple-access": "^7.16.0", "babel-plugin-dynamic-import-node": "^2.3.3" }, @@ -1287,14 +1283,14 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz", - "integrity": "sha512-yuGBaHS3lF1m/5R+6fjIke64ii5luRUg97N2wr+z1sF0V+sNSXPxXDdEEL/iYLszsN5VKxVB1IPfEqhzVpiqvg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.5.tgz", + "integrity": "sha512-53gmLdScNN28XpjEVIm7LbWnD/b/TpbwKbLk6KV4KqC9WyU6rq1jnNmVG6UgAdQZVVGZVoik3DqHNxk4/EvrjA==", "dev": true, "dependencies": { "@babel/helper-hoist-variables": "^7.16.0", - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-module-transforms": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/helper-validator-identifier": "^7.15.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, @@ -1306,13 +1302,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz", - "integrity": "sha512-nx4f6no57himWiHhxDM5pjwhae5vLpTK2zCnDH8+wNLJy0TVER/LJRHl2bkt6w9Aad2sPD5iNNoUpY3X9sTGDg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.5.tgz", + "integrity": "sha512-qTFnpxHMoenNHkS3VoWRdwrcJ3FhX567GvDA3hRZKF0Dj8Fmg0UzySZp3AP2mShl/bzcywb/UWAMQIjA1bhXvw==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-module-transforms": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1322,9 +1318,9 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz", - "integrity": "sha512-LogN88uO+7EhxWc8WZuQ8vxdSyVGxhkh8WTC3tzlT8LccMuQdA81e9SGV6zY7kY2LjDhhDOFdQVxdGwPyBCnvg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.5.tgz", + "integrity": "sha512-/wqGDgvFUeKELW6ex6QB7dLVRkd5ehjw34tpXu1nhKC0sFfmaLabIswnpf8JgDyV2NeDmZiwoOb0rAmxciNfjA==", "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.16.0" @@ -1337,12 +1333,12 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz", - "integrity": "sha512-fhjrDEYv2DBsGN/P6rlqakwRwIp7rBGLPbrKxwh7oVt5NNkIhZVOY2GRV+ULLsQri1bDqwDWnU3vhlmx5B2aCw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.5.tgz", + "integrity": "sha512-ZaIrnXF08ZC8jnKR4/5g7YakGVL6go6V9ql6Jl3ecO8PQaQqFE74CuM384kezju7Z9nGCCA20BqZaR1tJ/WvHg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1352,13 +1348,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz", - "integrity": "sha512-fds+puedQHn4cPLshoHcR1DTMN0q1V9ou0mUjm8whx9pGcNvDrVVrgw+KJzzCaiTdaYhldtrUps8DWVMgrSEyg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.5.tgz", + "integrity": "sha512-tded+yZEXuxt9Jdtkc1RraW1zMF/GalVxaVVxh41IYwirdRgyAxxxCKZ9XB7LxZqmsjfjALxupNE1MIz9KH+Zg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.16.0" + "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-replace-supers": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1368,12 +1364,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.16.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.3.tgz", - "integrity": "sha512-3MaDpJrOXT1MZ/WCmkOFo7EtmVVC8H4EUZVrHvFOsmwkk4lOjQj8rzv8JKUZV4YoQKeoIgk07GO+acPU9IMu/w==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.5.tgz", + "integrity": "sha512-B3O6AL5oPop1jAVg8CV+haeUte9oFuY85zu0jwnRNZZi3tVAbJriu5tag/oaO2kGaQM/7q7aGPBlTI5/sr9enA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1383,12 +1379,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz", - "integrity": "sha512-XLldD4V8+pOqX2hwfWhgwXzGdnDOThxaNTgqagOcpBgIxbUvpgU2FMvo5E1RyHbk756WYgdbS0T8y0Cj9FKkWQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.5.tgz", + "integrity": "sha512-+IRcVW71VdF9pEH/2R/Apab4a19LVvdVsr/gEeotH00vSDVlKD+XgfSIw+cgGWsjDB/ziqGv/pGoQZBIiQVXHg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1493,9 +1489,9 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz", - "integrity": "sha512-JAvGxgKuwS2PihiSFaDrp94XOzzTUeDeOQlcKzVAyaPap7BnZXK/lvMDiubkPTdotPKOIZq9xWXWnggUMYiExg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.5.tgz", + "integrity": "sha512-2z+it2eVWU8TtQQRauvGUqZwLy4+7rTfo6wO4npr+fvvN1SW30ZF3O/ZRCNmTuu4F5MIP8OJhXAhRV5QMJOuYg==", "dev": true, "dependencies": { "regenerator-transform": "^0.14.2" @@ -1508,12 +1504,12 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz", - "integrity": "sha512-Dgs8NNCehHSvXdhEhln8u/TtJxfVwGYCgP2OOr5Z3Ar+B+zXicEOKNTyc+eca2cuEOMtjW6m9P9ijOt8QdqWkg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.5.tgz", + "integrity": "sha512-aIB16u8lNcf7drkhXJRoggOxSTUAuihTSTfAcpynowGJOZiGf+Yvi7RuTwFzVYSYPmWyARsPqUGoZWWWxLiknw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1523,12 +1519,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz", - "integrity": "sha512-iVb1mTcD8fuhSv3k99+5tlXu5N0v8/DPm2mO3WACLG6al1CGZH7v09HJyUb1TtYl/Z+KrM6pHSIJdZxP5A+xow==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.5.tgz", + "integrity": "sha512-ZbuWVcY+MAXJuuW7qDoCwoxDUNClfZxoo7/4swVbOW1s/qYLOMHlm9YRWMsxMFuLs44eXsv4op1vAaBaBaDMVg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1538,12 +1534,12 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz", - "integrity": "sha512-Ao4MSYRaLAQczZVp9/7E7QHsCuK92yHRrmVNRe/SlEJjhzivq0BSn8mEraimL8wizHZ3fuaHxKH0iwzI13GyGg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.5.tgz", + "integrity": "sha512-5d6l/cnG7Lw4tGHEoga4xSkYp1euP7LAtrah1h1PgJ3JY7yNsjybsxQAnVK4JbtReZ/8z6ASVmd3QhYYKLaKZw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" }, "engines": { @@ -1554,12 +1550,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz", - "integrity": "sha512-/ntT2NljR9foobKk4E/YyOSwcGUXtYWv5tinMK/3RkypyNBNdhHUaq6Orw5DWq9ZcNlS03BIlEALFeQgeVAo4Q==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.5.tgz", + "integrity": "sha512-usYsuO1ID2LXxzuUxifgWtJemP7wL2uZtyrTVM4PKqsmJycdS4U4mGovL5xXkfUheds10Dd2PjoQLXw6zCsCbg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1569,12 +1565,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz", - "integrity": "sha512-Rd4Ic89hA/f7xUSJQk5PnC+4so50vBoBfxjdQAdvngwidM8jYIBVxBZ/sARxD4e0yMXRbJVDrYf7dyRtIIKT6Q==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.5.tgz", + "integrity": "sha512-gnyKy9RyFhkovex4BjKWL3BVYzUDG6zC0gba7VMLbQoDuqMfJ1SDXs8k/XK41Mmt1Hyp4qNAvGFb9hKzdCqBRQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1584,12 +1580,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz", - "integrity": "sha512-++V2L8Bdf4vcaHi2raILnptTBjGEFxn5315YU+e8+EqXIucA+q349qWngCLpUYqqv233suJ6NOienIVUpS9cqg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.5.tgz", + "integrity": "sha512-ldxCkW180qbrvyCVDzAUZqB0TAeF8W/vGJoRcaf75awm6By+PxfJKvuqVAnq8N9wz5Xa6mSpM19OfVKKVmGHSQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1599,12 +1595,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz", - "integrity": "sha512-VFi4dhgJM7Bpk8lRc5CMaRGlKZ29W9C3geZjt9beuzSUrlJxsNwX7ReLwaL6WEvsOf2EQkyIJEPtF8EXjB/g2A==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.5.tgz", + "integrity": "sha512-shiCBHTIIChGLdyojsKQjoAyB8MBwat25lKM7MJjbe1hE0bgIppD+LX9afr41lLHOhqceqeWl4FkLp+Bgn9o1Q==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1614,13 +1610,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz", - "integrity": "sha512-jHLK4LxhHjvCeZDWyA9c+P9XH1sOxRd1RO9xMtDVRAOND/PczPqizEtVdx4TQF/wyPaewqpT+tgQFYMnN/P94A==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.5.tgz", + "integrity": "sha512-GTJ4IW012tiPEMMubd7sD07iU9O/LOo8Q/oU4xNhcaq0Xn8+6TcUQaHtC8YxySo1T+ErQ8RaWogIEeFhKGNPzw==", "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" }, "engines": { "node": ">=6.9.0" @@ -1644,32 +1640,32 @@ "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" }, "node_modules/@babel/preset-env": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.4.tgz", - "integrity": "sha512-v0QtNd81v/xKj4gNKeuAerQ/azeNn/G1B1qMLeXOcV8+4TWlD2j3NV1u8q29SDFBXx/NBq5kyEAO+0mpRgacjA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.5.tgz", + "integrity": "sha512-MiJJW5pwsktG61NDxpZ4oJ1CKxM1ncam9bzRtx9g40/WkLRkxFP6mhpkYV0/DxcciqoiHicx291+eUQrXb/SfQ==", "dev": true, "dependencies": { "@babel/compat-data": "^7.16.4", "@babel/helper-compilation-targets": "^7.16.3", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/helper-validator-option": "^7.14.5", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.2", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-async-generator-functions": "^7.16.4", - "@babel/plugin-proposal-class-properties": "^7.16.0", - "@babel/plugin-proposal-class-static-block": "^7.16.0", - "@babel/plugin-proposal-dynamic-import": "^7.16.0", - "@babel/plugin-proposal-export-namespace-from": "^7.16.0", - "@babel/plugin-proposal-json-strings": "^7.16.0", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", - "@babel/plugin-proposal-numeric-separator": "^7.16.0", - "@babel/plugin-proposal-object-rest-spread": "^7.16.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-private-methods": "^7.16.0", - "@babel/plugin-proposal-private-property-in-object": "^7.16.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.0", + "@babel/plugin-proposal-async-generator-functions": "^7.16.5", + "@babel/plugin-proposal-class-properties": "^7.16.5", + "@babel/plugin-proposal-class-static-block": "^7.16.5", + "@babel/plugin-proposal-dynamic-import": "^7.16.5", + "@babel/plugin-proposal-export-namespace-from": "^7.16.5", + "@babel/plugin-proposal-json-strings": "^7.16.5", + "@babel/plugin-proposal-logical-assignment-operators": "^7.16.5", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.5", + "@babel/plugin-proposal-numeric-separator": "^7.16.5", + "@babel/plugin-proposal-object-rest-spread": "^7.16.5", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.5", + "@babel/plugin-proposal-optional-chaining": "^7.16.5", + "@babel/plugin-proposal-private-methods": "^7.16.5", + "@babel/plugin-proposal-private-property-in-object": "^7.16.5", + "@babel/plugin-proposal-unicode-property-regex": "^7.16.5", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", @@ -1684,38 +1680,38 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.0", - "@babel/plugin-transform-async-to-generator": "^7.16.0", - "@babel/plugin-transform-block-scoped-functions": "^7.16.0", - "@babel/plugin-transform-block-scoping": "^7.16.0", - "@babel/plugin-transform-classes": "^7.16.0", - "@babel/plugin-transform-computed-properties": "^7.16.0", - "@babel/plugin-transform-destructuring": "^7.16.0", - "@babel/plugin-transform-dotall-regex": "^7.16.0", - "@babel/plugin-transform-duplicate-keys": "^7.16.0", - "@babel/plugin-transform-exponentiation-operator": "^7.16.0", - "@babel/plugin-transform-for-of": "^7.16.0", - "@babel/plugin-transform-function-name": "^7.16.0", - "@babel/plugin-transform-literals": "^7.16.0", - "@babel/plugin-transform-member-expression-literals": "^7.16.0", - "@babel/plugin-transform-modules-amd": "^7.16.0", - "@babel/plugin-transform-modules-commonjs": "^7.16.0", - "@babel/plugin-transform-modules-systemjs": "^7.16.0", - "@babel/plugin-transform-modules-umd": "^7.16.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.0", - "@babel/plugin-transform-new-target": "^7.16.0", - "@babel/plugin-transform-object-super": "^7.16.0", - "@babel/plugin-transform-parameters": "^7.16.3", - "@babel/plugin-transform-property-literals": "^7.16.0", - "@babel/plugin-transform-regenerator": "^7.16.0", - "@babel/plugin-transform-reserved-words": "^7.16.0", - "@babel/plugin-transform-shorthand-properties": "^7.16.0", - "@babel/plugin-transform-spread": "^7.16.0", - "@babel/plugin-transform-sticky-regex": "^7.16.0", - "@babel/plugin-transform-template-literals": "^7.16.0", - "@babel/plugin-transform-typeof-symbol": "^7.16.0", - "@babel/plugin-transform-unicode-escapes": "^7.16.0", - "@babel/plugin-transform-unicode-regex": "^7.16.0", + "@babel/plugin-transform-arrow-functions": "^7.16.5", + "@babel/plugin-transform-async-to-generator": "^7.16.5", + "@babel/plugin-transform-block-scoped-functions": "^7.16.5", + "@babel/plugin-transform-block-scoping": "^7.16.5", + "@babel/plugin-transform-classes": "^7.16.5", + "@babel/plugin-transform-computed-properties": "^7.16.5", + "@babel/plugin-transform-destructuring": "^7.16.5", + "@babel/plugin-transform-dotall-regex": "^7.16.5", + "@babel/plugin-transform-duplicate-keys": "^7.16.5", + "@babel/plugin-transform-exponentiation-operator": "^7.16.5", + "@babel/plugin-transform-for-of": "^7.16.5", + "@babel/plugin-transform-function-name": "^7.16.5", + "@babel/plugin-transform-literals": "^7.16.5", + "@babel/plugin-transform-member-expression-literals": "^7.16.5", + "@babel/plugin-transform-modules-amd": "^7.16.5", + "@babel/plugin-transform-modules-commonjs": "^7.16.5", + "@babel/plugin-transform-modules-systemjs": "^7.16.5", + "@babel/plugin-transform-modules-umd": "^7.16.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.5", + "@babel/plugin-transform-new-target": "^7.16.5", + "@babel/plugin-transform-object-super": "^7.16.5", + "@babel/plugin-transform-parameters": "^7.16.5", + "@babel/plugin-transform-property-literals": "^7.16.5", + "@babel/plugin-transform-regenerator": "^7.16.5", + "@babel/plugin-transform-reserved-words": "^7.16.5", + "@babel/plugin-transform-shorthand-properties": "^7.16.5", + "@babel/plugin-transform-spread": "^7.16.5", + "@babel/plugin-transform-sticky-regex": "^7.16.5", + "@babel/plugin-transform-template-literals": "^7.16.5", + "@babel/plugin-transform-typeof-symbol": "^7.16.5", + "@babel/plugin-transform-unicode-escapes": "^7.16.5", + "@babel/plugin-transform-unicode-regex": "^7.16.5", "@babel/preset-modules": "^0.1.5", "@babel/types": "^7.16.0", "babel-plugin-polyfill-corejs2": "^0.3.0", @@ -1757,9 +1753,9 @@ } }, "node_modules/@babel/register": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.16.0.tgz", - "integrity": "sha512-lzl4yfs0zVXnooeLE0AAfYaT7F3SPA8yB2Bj4W1BiZwLbMS3MZH35ZvCWSRHvneUugwuM+Wsnrj7h0F7UmU3NQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.16.5.tgz", + "integrity": "sha512-NpluD+cToBiZiDsG3y9rtIcqDyivsahpaM9csfyfiq1qQWduSmihUZ+ruIqqSDGjZKZMJfgAElo9x2YWlOQuRw==", "dev": true, "dependencies": { "clone-deep": "^4.0.1", @@ -1787,9 +1783,9 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.16.3", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.3.tgz", - "integrity": "sha512-IAdDC7T0+wEB4y2gbIL0uOXEYpiZEeuFUTVbdGq+UwCcF35T/tS8KrmMomEwEc5wBbyfH3PJVpTSUqrhPDXFcQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.5.tgz", + "integrity": "sha512-F1pMwvTiUNSAM8mc45kccMQxj31x3y3P+tA/X8hKNWp3/hUsxdGxZ3D3H8JIkxtfA8qGkaBTKvcmvStaYseAFw==", "dev": true, "dependencies": { "core-js-pure": "^3.19.0", @@ -1814,17 +1810,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.16.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.3.tgz", - "integrity": "sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.5.tgz", + "integrity": "sha512-FOCODAzqUMROikDYLYxl4nmwiLlu85rNqBML/A5hKRVXG2LV8d0iMqgPzdYTcIpjZEBB7D6UDU9vxRZiriASdQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.0", + "@babel/generator": "^7.16.5", + "@babel/helper-environment-visitor": "^7.16.5", "@babel/helper-function-name": "^7.16.0", "@babel/helper-hoist-variables": "^7.16.0", "@babel/helper-split-export-declaration": "^7.16.0", - "@babel/parser": "^7.16.3", + "@babel/parser": "^7.16.5", "@babel/types": "^7.16.0", "debug": "^4.1.0", "globals": "^11.1.0" @@ -2867,33 +2864,20 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.13.0.tgz", - "integrity": "sha512-APVqbVPGOprb4BmjEnwbSzV+V2e/6DVIUnZG3zdW5uWXWkN0DKMCpiIy2TdBauoANKYO7RQpO8cTjIYNVSKwUA==", - "dev": true, - "dependencies": { - "comment-parser": "1.3.0", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "2.0.0" - }, - "engines": { - "node": "^12 || ^14 || ^16 || ^17" - } - }, "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", + "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.1.1", "espree": "^7.3.0", - "globals": "^13.9.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, @@ -2902,9 +2886,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -2918,27 +2902,13 @@ } } }, - "node_modules/@eslint/eslintrc/node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", - "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", "dev": true, "dependencies": { - "type-fest": "^0.20.2" + "type-fest": "^0.8.1" }, "engines": { "node": ">=8" @@ -2956,70 +2926,12 @@ "node": ">= 4" } }, - "node_modules/@eslint/eslintrc/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/eslintrc/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/@eslint/eslintrc/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@fintechstudios/eslint-plugin-chai-as-promised": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@fintechstudios/eslint-plugin-chai-as-promised/-/eslint-plugin-chai-as-promised-3.1.0.tgz", - "integrity": "sha512-Y3TmITTwc5u8hoW0GWxle1hKiVadDqDHyLQaTv+e+xVDHazn361QIEY9NbWqNsXP0jzrSskpnhkBr++h+PciEw==", - "dev": true, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/@hapi/hoek": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz", @@ -3035,49 +2947,6 @@ "@hapi/hoek": "^9.0.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", - "dev": true - }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -3540,12 +3409,6 @@ "regenerator-runtime": "^0.13.3" } }, - "node_modules/@mdn/browser-compat-data": { - "version": "3.3.14", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-3.3.14.tgz", - "integrity": "sha512-n2RC9d6XatVbWFdHLimzzUJxJ1KY8LdjqrW6YvGPiRmsHkhOUx74/Ct10x5Yo7bC/Jvqx7cDEW8IMPv/+vwEzA==", - "dev": true - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", @@ -3785,9 +3648,9 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.6.tgz", - "integrity": "sha512-sFsPDMPd4gMqnh2gS0uIxELnoRUp5kBl5knxD2EO0778G1oOJv4G1vyT2cpWz75OU2jDVcXhjVUuTAczGyFNKA==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.1.tgz", + "integrity": "sha512-6QKtRevXLrmEig9UiMYt2fSvee9TyltGRfw+qSs6xjUnxwjOzTOqy+/Lpxsgjb8mJn1EQNbCDAvt89O4uzL5kw==", "dev": true, "dependencies": { "@rollup/pluginutils": "^3.1.0", @@ -4529,34 +4392,6 @@ "node": ">=8.0" } }, - "node_modules/@web/dev-server-esbuild": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/@web/dev-server-esbuild/-/dev-server-esbuild-0.2.16.tgz", - "integrity": "sha512-a82uKy9vQ4HvfWtjd7hJ3GtaqkL2ofxpEu3a1wIZyXB2dFWPvhRSmLNe/4IPPHe4vj6PVdRpLSFPEA3lXUW5Pw==", - "dev": true, - "dependencies": { - "@mdn/browser-compat-data": "^4.0.0", - "@web/dev-server-core": "^0.3.17", - "esbuild": "^0.12.21", - "parse5": "^6.0.1", - "ua-parser-js": "^1.0.2" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@web/dev-server-esbuild/node_modules/@mdn/browser-compat-data": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-4.1.0.tgz", - "integrity": "sha512-58eB5/ovJ5CfArzZwmZdenF/WlAGGS+1PG8RUb3oJ4st9exETBjClmFC0E1uVrZG1BwPaT205RKS8RhnUh5x3Q==", - "dev": true - }, - "node_modules/@web/dev-server-esbuild/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "node_modules/@web/dev-server-rollup": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@web/dev-server-rollup/-/dev-server-rollup-0.3.13.tgz", @@ -4766,9 +4601,9 @@ } }, "node_modules/acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -4987,9 +4822,9 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "engines": { "node": ">=8" @@ -5180,6 +5015,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.flatmap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", + "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", @@ -5265,15 +5117,6 @@ "node": ">=0.10.0" } }, - "node_modules/ast-metadata-inferer": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.7.0.tgz", - "integrity": "sha512-OkMLzd8xelb3gmnp6ToFvvsHLtS6CbagTkFQvQ+ZYFe3/AIl9iKikNR9G7pY3GfOR/2Xc222hwBjzI7HLkE76Q==", - "dev": true, - "dependencies": { - "@mdn/browser-compat-data": "^3.3.14" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -6646,15 +6489,6 @@ "node": ">= 6" } }, - "node_modules/comment-parser": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.0.tgz", - "integrity": "sha512-hRpmWIKgzd81vn0ydoWoyPoALEOnF4wt8yKD35Ib1D6XC2siLiYaiqfGkYrunuKdsXGwpBpHU3+9r+RVw2NZfA==", - "dev": true, - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/common-tags": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", @@ -6920,9 +6754,9 @@ } }, "node_modules/core-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.3.tgz", - "integrity": "sha512-LeLBMgEGSsG7giquSzvgBrTS7V5UL6ks3eQlUSbN8dJStlLFiRzUm5iqsRyzUB8carhfKjkJ2vzKqE6z1Vga9g==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.1.tgz", + "integrity": "sha512-btdpStYFQScnNVQ5slVcr858KP0YWYjV16eGJQw8Gg7CWtu/2qNvIM3qVRIR3n1pK2R9NNOrTevbvAYxajwEjg==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -6930,9 +6764,9 @@ } }, "node_modules/core-js-bundle": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/core-js-bundle/-/core-js-bundle-3.19.3.tgz", - "integrity": "sha512-mzXBG3MkmPpBEVAPCIPx9QAle9mEkuZyuMv7Zivp0bgTG/b9BOZ7rTibYomh9zR0dKc6bM8yyco0zaLuZAv9bQ==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/core-js-bundle/-/core-js-bundle-3.20.1.tgz", + "integrity": "sha512-WP0sI7ge37iSWwaQmGIL2mtGvJah/KgC9FzAz0CZljXJqqZxvr8enzdjuxsoZ6jTr/Ya6MvDc0sKECUkLI/Nmw==", "dev": true, "hasInstallScript": true, "funding": { @@ -7313,9 +7147,9 @@ "dev": true }, "node_modules/cypress": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.1.1.tgz", - "integrity": "sha512-yWcYD8SEQ8F3okFbRPqSDj5V0xhrZBT5QRIH+P1J2vYvtEmZ4KGciHE7LCcZZLILOrs7pg4WNCqkj/XRvReQlQ==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.2.0.tgz", + "integrity": "sha512-Jn26Tprhfzh/a66Sdj9SoaYlnNX6Mjfmj5PHu2a7l3YHXhrgmavM368wjCmgrxC6KHTOv9SpMQGhAJn+upDViA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -7991,20 +7825,6 @@ "node": ">=6.0.0" } }, - "node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, "node_modules/dom-walk": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", @@ -8021,18 +7841,6 @@ "npm": ">=1.2" } }, - "node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, "node_modules/domexception": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", @@ -8054,41 +7862,12 @@ "node": ">=8" } }, - "node_modules/domhandler": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", - "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, "node_modules/dompurify": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.2.6.tgz", "integrity": "sha512-7b7ZArhhH0SP6W2R9cqK6RjaU82FZ2UPM7RO8qN1b1wyvC/NY1FNWcX1Pu00fFOAnzEORtwXe4bPaClg6pUybQ==", "devOptional": true }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, "node_modules/duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -8398,16 +8177,6 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, - "node_modules/esbuild": { - "version": "0.12.29", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.29.tgz", - "integrity": "sha512-w/XuoBCSwepyiZtIRsKsetiLDUVGPVw1E/R3VTFSecIy8UR7Cq3SOtwKHJMFoVqqVG36aGkzh4e8BvpO1Fdc7g==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - } - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -8465,32 +8234,29 @@ } }, "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz", + "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==", "dev": true, "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.3.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.0.1", "doctrine": "^3.0.0", "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", "eslint-scope": "^5.1.1", "eslint-utils": "^2.1.0", "eslint-visitor-keys": "^2.0.0", "espree": "^7.3.1", - "esquery": "^1.4.0", + "esquery": "^1.2.0", "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^6.0.0", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -8498,7 +8264,7 @@ "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash.merge": "^4.6.2", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", @@ -8507,7 +8273,7 @@ "semver": "^7.2.1", "strip-ansi": "^6.0.0", "strip-json-comments": "^3.1.0", - "table": "^6.0.9", + "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -8547,6 +8313,30 @@ "eslint-plugin-promise": "^4.2.1 || ^5.0.0" } }, + "node_modules/eslint-config-standard-jsx": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-10.0.0.tgz", + "integrity": "sha512-hLeA2f5e06W1xyr/93/QJulN/rLbUVUmqTlexv9PRKHFwEC9ffJcH2LvJhMoEqYQBEYafedgGZXH2W8NUpt5lA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peerDependencies": { + "eslint": "^7.12.1", + "eslint-plugin-react": "^7.21.5" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", @@ -8671,200 +8461,12 @@ "node": ">=4" } }, - "node_modules/eslint-plugin-array-func": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/eslint-plugin-array-func/-/eslint-plugin-array-func-3.1.7.tgz", - "integrity": "sha512-fB5TBICjHSTGToNTbCCgR8zsngpUkoCM31EMh/M/NEAyNg90i5rUuG0dnNNBML2n0BzM0nBE3sPvo2SEWf6jlA==", - "dev": true, - "engines": { - "node": ">= 6.8.0" - } - }, - "node_modules/eslint-plugin-chai-expect": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-chai-expect/-/eslint-plugin-chai-expect-3.0.0.tgz", - "integrity": "sha512-NS0YBcToJl+BRKBSMCwRs/oHJIX67fG5Gvb4tGked+9Wnd1/PzKijd82B2QVKcSSOwRe+pp4RAJ2AULeck4eQw==", - "dev": true, - "engines": { - "node": "10.* || 12.* || >= 14.*" - }, - "peerDependencies": { - "eslint": ">=2.0.0 <= 8.x" - } - }, - "node_modules/eslint-plugin-chai-expect-keywords": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-chai-expect-keywords/-/eslint-plugin-chai-expect-keywords-2.1.0.tgz", - "integrity": "sha512-3F4QgEGQqAO7DXXltNKyw8JaSIHniUfhJHO75GnOwKlhz6bIKFxyXtySxSZAx6v1/CwCDp7kjYY/YPHJJFsYPA==", - "dev": true, - "engines": { - "node": ">=8.3.0" - } - }, - "node_modules/eslint-plugin-chai-friendly": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.7.2.tgz", - "integrity": "sha512-LOIfGx5sZZ5FwM1shr2GlYAWV9Omdi+1/3byuVagvQNoGUuU0iHhp7AfjA1uR+4dJ4Isfb4+FwBJgQajIw9iAg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "eslint": ">=3.0.0" - } - }, - "node_modules/eslint-plugin-compat": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-4.0.0.tgz", - "integrity": "sha512-lg9CPq0bsGxNXcLZgxqVAYsUUELIKZPRiwnJJQOHH910zCHEiscO00Sp+w9wflKEa/OtVaYfNhI2jOViRPZtjw==", - "dev": true, - "dependencies": { - "@mdn/browser-compat-data": "^3.3.14", - "ast-metadata-inferer": "^0.7.0", - "browserslist": "^4.16.8", - "caniuse-lite": "^1.0.30001267", - "core-js": "^3.16.2", - "find-up": "^5.0.0", - "lodash.memoize": "4.1.2", - "semver": "7.3.5" - }, - "engines": { - "node": ">=9.x" - }, - "peerDependencies": { - "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/eslint-plugin-compat/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-compat/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-compat/node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "node_modules/eslint-plugin-compat/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-compat/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-compat/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint-plugin-compat/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-cypress": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.12.1.tgz", - "integrity": "sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA==", - "dev": true, - "dependencies": { - "globals": "^11.12.0" - }, - "peerDependencies": { - "eslint": ">= 3.2.1" - } - }, - "node_modules/eslint-plugin-eslint-comments": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", - "integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5", - "ignore": "^5.0.5" - }, - "engines": { - "node": ">=6.5.0" - } - }, - "node_modules/eslint-plugin-html": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-6.2.0.tgz", - "integrity": "sha512-vi3NW0E8AJombTvt8beMwkL1R/fdRWl4QSNRNMhVQKWm36/X0KF0unGNAY4mqUF06mnwVWZcIcerrCnfn9025g==", - "dev": true, - "dependencies": { - "htmlparser2": "^7.1.2" - } - }, "node_modules/eslint-plugin-import": { "version": "2.25.3", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==", "dev": true, + "peer": true, "dependencies": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", @@ -8892,6 +8494,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "peer": true, "dependencies": { "esutils": "^2.0.2" }, @@ -8899,118 +8502,6 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-jsdoc": { - "version": "37.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-37.2.0.tgz", - "integrity": "sha512-ca7s/DD1mMObZQ2Y0n0DO/KnFV+FqCX6ztir8pcSuylg3GGCREIisn36P/0cRySuWW/7Y7MNCuUDqtKdgLPU7Q==", - "dev": true, - "dependencies": { - "@es-joy/jsdoccomment": "0.13.0", - "comment-parser": "1.3.0", - "debug": "^4.3.3", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "^2.0.0", - "regextras": "^0.8.0", - "semver": "^7.3.5", - "spdx-expression-parse": "^3.0.1" - }, - "engines": { - "node": "^12 || ^14 || ^16 || ^17" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/eslint-plugin-jsdoc/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-markdown": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-2.2.1.tgz", - "integrity": "sha512-FgWp4iyYvTFxPwfbxofTvXxgzPsDuSKHQy2S+a8Ve6savbujey+lgrFFbXQA0HPygISpRYWYBjooPzhYSF81iA==", - "dev": true, - "dependencies": { - "mdast-util-from-markdown": "^0.8.5" - }, - "engines": { - "node": "^8.10.0 || ^10.12.0 || >= 12.0.0" - }, - "peerDependencies": { - "eslint": ">=6.0.0" - } - }, - "node_modules/eslint-plugin-no-unsanitized": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.1.tgz", - "integrity": "sha512-y/lAMWnPPC7RYuUdxlEL/XiCL8FehN9h9s3Kjqbp/Kv0i9NZs+IXSC2kS546Fa4Bumwy31HlVS/OdWX0Kxb5Xg==", - "dev": true, - "peerDependencies": { - "eslint": "^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-no-use-extend-native": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-no-use-extend-native/-/eslint-plugin-no-use-extend-native-0.5.0.tgz", - "integrity": "sha512-dBNjs8hor8rJgeXLH4HTut5eD3RGWf9JUsadIfuL7UosVQ/dnvOKwxEcRrXrFxrMZ8llUVWT+hOimxJABsAUzQ==", - "dev": true, - "dependencies": { - "is-get-set-prop": "^1.0.0", - "is-js-type": "^2.0.0", - "is-obj-prop": "^1.0.0", - "is-proto-prop": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/eslint-plugin-node": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", @@ -9041,27 +8532,6 @@ "node": ">=8.10.0" } }, - "node_modules/eslint-plugin-node/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-plugin-node/node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/eslint-plugin-node/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -9072,22 +8542,106 @@ } }, "node_modules/eslint-plugin-promise": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz", - "integrity": "sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz", + "integrity": "sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==", "dev": true, + "peer": true, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "peerDependencies": { - "eslint": "^7.0.0" + "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/eslint-plugin-standard": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.1.0.tgz", - "integrity": "sha512-ZL7+QRixjTR6/528YNGyDotyffm5OQst/sGxKDwGb9Uqs4In5Egi4+jbobhqJoyoCM6/7v/1A5fhQ7ScMtDjaQ==", - "dev": true + "node_modules/eslint-plugin-react": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.25.3.tgz", + "integrity": "sha512-ZMbFvZ1WAYSZKY662MBVEWR45VaBT6KSJCiupjrNlcdakB90juaZeDCbJq19e73JZQubqFtgETohwgAt8u5P6w==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", + "doctrine": "^2.1.0", + "estraverse": "^5.2.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.4", + "object.fromentries": "^2.0.4", + "object.hasown": "^1.0.0", + "object.values": "^1.1.4", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "string.prototype.matchall": "^4.0.5" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } }, "node_modules/eslint-visitor-keys": { "version": "1.3.0", @@ -9098,15 +8652,6 @@ "node": ">=4" } }, - "node_modules/eslint/node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -9151,116 +8696,31 @@ "dev": true }, "node_modules/eslint/node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "dependencies": { "ms": "2.1.2" }, "engines": { "node": ">=6.0" - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, "engines": { "node": ">=10" } }, - "node_modules/eslint/node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/eslint/node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/eslint/node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -9274,15 +8734,18 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.6.0.tgz", - "integrity": "sha512-YFKCX0SiPg7l5oKYCJ2zZGxcXprVXHcSnVuvzrT3oSENQonVLqM5pf9fN5dLGZGyCjhw8TN8Btwe/jKnZ0pjvQ==", + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", "dev": true, "dependencies": { - "type-fest": "^0.20.2" + "type-fest": "^0.8.1" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint/node_modules/has-flag": { @@ -9303,19 +8766,6 @@ "node": ">= 4" } }, - "node_modules/eslint/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/eslint/node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -9361,24 +8811,6 @@ "node": ">= 0.8.0" } }, - "node_modules/eslint/node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/eslint/node_modules/semver": { "version": "7.3.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", @@ -9394,15 +8826,6 @@ "node": ">=10" } }, - "node_modules/eslint/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9427,13 +8850,18 @@ "node": ">= 0.8.0" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, "engines": { - "node": ">=10" + "node": "^10.12.0 || >=12.0.0" } }, "node_modules/esprima": { @@ -9470,6 +8898,27 @@ "node": ">=4.0" } }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", @@ -10386,15 +9835,6 @@ "node": ">=8.0.0" } }, - "node_modules/get-set-props": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-set-props/-/get-set-props-0.1.0.tgz", - "integrity": "sha1-mYR1wXhEVobQsyJG2l3428++jqM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/get-stdin": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", @@ -10917,37 +10357,6 @@ "node": ">=0.10" } }, - "node_modules/htmlparser2": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.1.2.tgz", - "integrity": "sha512-d6cqsbJba2nRdg8WW2okyD4ceonFHn9jLFxhwlNcLhQWcFPdxXeJulgOLjLKtAK9T6ahd+GQNZwG9fjmGW7lyg==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.2", - "domutils": "^2.8.0", - "entities": "^3.0.1" - } - }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/http-assert": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz", @@ -11086,9 +10495,9 @@ } }, "node_modules/i18next": { - "version": "21.6.0", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.0.tgz", - "integrity": "sha512-RjNuACL35wWZgtkyMcjcCmK7R72u3P6jTNbGKzrvHGI9M0iK5Vn1DsBIwOByppaXLIbe0viJ79Nz2h8w1UwPoQ==", + "version": "21.6.4", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.4.tgz", + "integrity": "sha512-pk0Utxtq5g//Q9ONQ0w3+PRSwOFJ7+m4rAekhHHg1Xql0KcUjJU7DzmzweGy6DsrIQ1GM/t57wLeeGuyGKtjTg==", "dependencies": { "@babel/runtime": "^7.12.0" } @@ -11155,6 +10564,31 @@ "node": ">=6.9.0" } }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/import-meta-resolve": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-1.1.1.tgz", @@ -11547,16 +10981,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-get-set-prop": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-get-set-prop/-/is-get-set-prop-1.0.0.tgz", - "integrity": "sha1-JzGHfk14pqae3M5rudaLB3nnYxI=", - "dev": true, - "dependencies": { - "get-set-props": "^0.1.0", - "lowercase-keys": "^1.0.0" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -11575,15 +10999,6 @@ "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", "dev": true }, - "node_modules/is-js-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-js-type/-/is-js-type-2.0.0.tgz", - "integrity": "sha1-c2FwBtZZtOtHKbunR9KHgt8PfiI=", - "dev": true, - "dependencies": { - "js-types": "^1.0.0" - } - }, "node_modules/is-lambda": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", @@ -11644,16 +11059,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-obj-prop": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-obj-prop/-/is-obj-prop-1.0.0.tgz", - "integrity": "sha1-s03nnEULjXxzqyzfZ9yHWtuF+A4=", - "dev": true, - "dependencies": { - "lowercase-keys": "^1.0.0", - "obj-props": "^1.0.0" - } - }, "node_modules/is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -11699,16 +11104,6 @@ "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", "dev": true }, - "node_modules/is-proto-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-proto-prop/-/is-proto-prop-2.0.0.tgz", - "integrity": "sha512-jl3NbQ/fGLv5Jhan4uX+Ge9ohnemqyblWVVCpAvtTQzNFvV2xhJq+esnkIbYQ9F1nITXoLfDDQLp7LBw/zzncg==", - "dev": true, - "dependencies": { - "lowercase-keys": "^1.0.0", - "proto-props": "^2.0.0" - } - }, "node_modules/is-reference": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", @@ -12177,15 +11572,6 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, - "node_modules/js-types": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/js-types/-/js-types-1.0.0.tgz", - "integrity": "sha1-0kLmSU7Vcq08koCfyL7X92h8vwM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/js-yaml": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", @@ -12242,15 +11628,6 @@ "node": ">=8.15.0" } }, - "node_modules/jsdoc-type-pratt-parser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-2.0.0.tgz", - "integrity": "sha512-sUuj2j48wxrEpbFjDp1sAesAxPiLT+z0SWVmMafyIINs6Lj5gIPKh3VrkBZu4E/Dv+wHpOot0m6H8zlHQjwqeQ==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/jsdoc/node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -12278,15 +11655,6 @@ "node": ">=10" } }, - "node_modules/jsdoc/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jsdom": { "version": "16.4.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", @@ -12438,9 +11806,9 @@ } }, "node_modules/jspdf": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.4.0.tgz", - "integrity": "sha512-nsZ92YfbNG/EimR1yqmOkxf2D4iJRypBsw7pvP1aPiIEnoGITaLl6XDR/GYA36/R29vMZSBedpEhBCzutSGytA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.0.tgz", + "integrity": "sha512-XT0E2m8A9P1xl7ItA2OUbmhokzbDQEyZEdWQZD2olADiTiBEZGDRiK1J1zWxBRUG2KezQJOZq//GYZTkvEZuJg==", "dependencies": { "@babel/runtime": "^7.14.0", "atob": "^2.1.2", @@ -12469,6 +11837,19 @@ "verror": "1.10.0" } }, + "node_modules/jsx-ast-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", + "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.3", + "object.assign": "^4.1.2" + }, + "engines": { + "node": ">=4.0" + } + }, "node_modules/keygrip": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", @@ -12938,12 +12319,6 @@ "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", "dev": true }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -13138,15 +12513,6 @@ "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", "dev": true }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -15425,16 +14791,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/mocha/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -16250,15 +15606,6 @@ "node": "*" } }, - "node_modules/obj-props": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/obj-props/-/obj-props-1.3.0.tgz", - "integrity": "sha512-k2Xkjx5wn6eC3537SWAXHzB6lkI81kS+icMKMkh4nG3w7shWG6MaWOBrNvhWVOszrtL5uxdfymQQfPUxwY+2eg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -16407,6 +15754,50 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -17173,6 +16564,53 @@ "pixelmatch": "bin/pixelmatch" } }, + "node_modules/pkg-conf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", + "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0", + "load-json-file": "^5.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-conf/node_modules/load-json-file": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-conf/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/pkg-dir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", @@ -17185,6 +16623,76 @@ "node": ">=6" } }, + "node_modules/pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/pngjs": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", @@ -17320,13 +16828,15 @@ "node": ">=10" } }, - "node_modules/proto-props": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/proto-props/-/proto-props-2.0.0.tgz", - "integrity": "sha512-2yma2tog9VaRZY2mn3Wq51uiSW4NcPYT1cQdBagwyrznrilKSZwIZ0UG3ZPL/mx+axEns0hE35T5ufOYZXEnBQ==", + "node_modules/prop-types": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.0.tgz", + "integrity": "sha512-fDGekdaHh65eI3lMi5OnErU6a8Ighg2KjcjQxO7m8VHyWjcPyj5kiOgV1LQDOOOgVy3+5FgjXvdSSX7B8/5/4g==", "dev": true, - "engines": { - "node": ">=4" + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, "node_modules/proxy-from-env": { @@ -17479,6 +16989,12 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, "node_modules/read-only-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", @@ -17515,6 +17031,77 @@ "node": ">=4" } }, + "node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/read-pkg/node_modules/path-type": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", @@ -17703,6 +17290,34 @@ "node": ">=0.10.0" } }, + "node_modules/regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/regexpu-core": { "version": "4.8.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", @@ -17720,15 +17335,6 @@ "node": ">=4" } }, - "node_modules/regextras": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.8.0.tgz", - "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==", - "dev": true, - "engines": { - "node": ">=0.1.14" - } - }, "node_modules/regjsgen": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", @@ -18782,9 +18388,9 @@ } }, "node_modules/rollup": { - "version": "2.61.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.61.0.tgz", - "integrity": "sha512-teQ+T1mUYbyvGyUavCodiyA9hD4DxwYZJwr/qehZGhs1Z49vsmzelMVYMxGU4ZhGRKxYPupHuz5yzm/wj7VpWA==", + "version": "2.62.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.62.0.tgz", + "integrity": "sha512-cJEQq2gwB0GWMD3rYImefQTSjrPYaC6s4J9pYqnstVLJ1CHa/aZNVkD4Epuvg4iLeMA4KRiq7UM7awKK6j7jcw==", "bin": { "rollup": "dist/bin/rollup" }, @@ -20022,6 +19628,194 @@ "node": ">=0.1.14" } }, + "node_modules/standard": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/standard/-/standard-16.0.4.tgz", + "integrity": "sha512-2AGI874RNClW4xUdM+bg1LRXVlYLzTNEkHmTG5mhyn45OhbgwA+6znowkOGYy+WMb5HRyELvtNy39kcdMQMcYQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "eslint": "~7.18.0", + "eslint-config-standard": "16.0.3", + "eslint-config-standard-jsx": "10.0.0", + "eslint-plugin-import": "~2.24.2", + "eslint-plugin-node": "~11.1.0", + "eslint-plugin-promise": "~5.1.0", + "eslint-plugin-react": "~7.25.1", + "standard-engine": "^14.0.1" + }, + "bin": { + "standard": "bin/cmd.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/standard-engine": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-14.0.1.tgz", + "integrity": "sha512-7FEzDwmHDOGva7r9ifOzD3BGdTbA7ujJ50afLVdW/tK14zQEptJjbFuUfn50irqdHDcTbNh0DTIoMPynMCXb0Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "get-stdin": "^8.0.0", + "minimist": "^1.2.5", + "pkg-conf": "^3.1.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8.10" + } + }, + "node_modules/standard-engine/node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/standard/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/standard/node_modules/eslint-plugin-import": { + "version": "2.24.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz", + "integrity": "sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.6.2", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.6.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.4", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + } + }, + "node_modules/standard/node_modules/eslint-plugin-promise": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.1.tgz", + "integrity": "sha512-XgdcdyNzHfmlQyweOPTxmc7pIsS6dE4MvwhXWMQ2Dxs1XAL2GJDilUsjWen6TWik0aSI+zD/PqocZBblcm9rdA==", + "dev": true, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0" + } + }, + "node_modules/standard/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/standard/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/standard/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/standard/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/standard/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/start-server-and-test": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.14.0.tgz", @@ -20294,19 +20088,38 @@ } }, "node_modules/string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, + "node_modules/string.prototype.matchall": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", + "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/string.prototype.padend": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz", @@ -20347,12 +20160,12 @@ } }, "node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -20400,6 +20213,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strtok3": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.1.3.tgz", @@ -20481,17 +20306,16 @@ } }, "node_modules/table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.5.tgz", + "integrity": "sha512-LFNeryOqiQHqCVKzhkymKwt6ozeRhlm8IL1mE8rNUurkir4heF6PzMyRgaTa4tlyPTGGgXuvVOF/OLWiH09Lqw==", "dev": true, "dependencies": { "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=10.0.0" @@ -20531,9 +20355,9 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz", - "integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==", + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz", + "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -21259,25 +21083,6 @@ "node": ">=8" } }, - "node_modules/ua-parser-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", - "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - } - ], - "engines": { - "node": "*" - } - }, "node_modules/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -23062,6 +22867,15 @@ } } }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/xhr": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz", @@ -23339,19 +23153,19 @@ "dev": true }, "@babel/core": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.0.tgz", - "integrity": "sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.5.tgz", + "integrity": "sha512-wUcenlLzuWMZ9Zt8S0KmFwGlH6QKRh3vsm/dhDA3CHkiTA45YuG1XkHRcNRl73EFPXDp/d5kVOU0/y7x2w6OaQ==", "dev": true, "requires": { "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.0", - "@babel/helper-compilation-targets": "^7.16.0", - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helpers": "^7.16.0", - "@babel/parser": "^7.16.0", + "@babel/generator": "^7.16.5", + "@babel/helper-compilation-targets": "^7.16.3", + "@babel/helper-module-transforms": "^7.16.5", + "@babel/helpers": "^7.16.5", + "@babel/parser": "^7.16.5", "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", + "@babel/traverse": "^7.16.5", "@babel/types": "^7.16.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", @@ -23385,9 +23199,9 @@ } }, "@babel/generator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.0.tgz", - "integrity": "sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.5.tgz", + "integrity": "sha512-kIvCdjZqcdKqoDbVVdt5R99icaRtrtYhYK/xux5qiWCBmfdvEYMFZ68QCrpE5cbFM1JsuArUNs1ZkuKtTtUcZA==", "dev": true, "requires": { "@babel/types": "^7.16.0", @@ -23405,9 +23219,9 @@ } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.0.tgz", - "integrity": "sha512-9KuleLT0e77wFUku6TUkqZzCEymBdtuQQ27MhEKzf9UOOJu3cYj98kyaDAzxpC7lV6DGiZFuC8XqDsq8/Kl6aQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.5.tgz", + "integrity": "sha512-3JEA9G5dmmnIWdzaT9d0NmFRgYnWUThLsDaL7982H0XqqWr56lRrsmwheXFMjR+TMl7QMBb6mzy9kvgr1lRLUA==", "dev": true, "requires": { "@babel/helper-explode-assignable-expression": "^7.16.0", @@ -23435,16 +23249,17 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz", - "integrity": "sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.5.tgz", + "integrity": "sha512-NEohnYA7mkB8L5JhU7BLwcBdU3j83IziR9aseMueWGeAjblbul3zzb8UvJ3a1zuBiqCMObzCJHFqKIQE6hTVmg==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.16.0", + "@babel/helper-environment-visitor": "^7.16.5", "@babel/helper-function-name": "^7.16.0", - "@babel/helper-member-expression-to-functions": "^7.16.0", + "@babel/helper-member-expression-to-functions": "^7.16.5", "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/helper-replace-supers": "^7.16.0", + "@babel/helper-replace-supers": "^7.16.5", "@babel/helper-split-export-declaration": "^7.16.0" } }, @@ -23497,6 +23312,15 @@ } } }, + "@babel/helper-environment-visitor": { + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz", + "integrity": "sha512-ODQyc5AnxmZWm/R2W7fzhamOk1ey8gSguo5SGvF0zcB3uUzRpTRmM/jmLSm9bDMyPlvbyJ+PwPEK0BWIoZ9wjg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.0" + } + }, "@babel/helper-explode-assignable-expression": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz", @@ -23536,9 +23360,9 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz", - "integrity": "sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.5.tgz", + "integrity": "sha512-7fecSXq7ZrLE+TWshbGT+HyCLkxloWNhTbU2QM1NTI/tDqyf0oZiMcEfYtDuUDCo528EOlt39G1rftea4bRZIw==", "dev": true, "requires": { "@babel/types": "^7.16.0" @@ -23554,18 +23378,18 @@ } }, "@babel/helper-module-transforms": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz", - "integrity": "sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.5.tgz", + "integrity": "sha512-CkvMxgV4ZyyioElFwcuWnDCcNIeyqTkCm9BxXZi73RR1ozqlpboqsbGUNvRTflgZtFbbJ1v5Emvm+lkjMYY/LQ==", "dev": true, "requires": { + "@babel/helper-environment-visitor": "^7.16.5", "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-replace-supers": "^7.16.0", "@babel/helper-simple-access": "^7.16.0", "@babel/helper-split-export-declaration": "^7.16.0", "@babel/helper-validator-identifier": "^7.15.7", "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", + "@babel/traverse": "^7.16.5", "@babel/types": "^7.16.0" } }, @@ -23579,31 +23403,32 @@ } }, "@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz", + "integrity": "sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==", "dev": true }, "@babel/helper-remap-async-to-generator": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.4.tgz", - "integrity": "sha512-vGERmmhR+s7eH5Y/cp8PCVzj4XEjerq8jooMfxFdA5xVtAk9Sh4AQsrWgiErUEBjtGrBtOFKDUcWQFW4/dFwMA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.5.tgz", + "integrity": "sha512-X+aAJldyxrOmN9v3FKp+Hu1NO69VWgYgDGq6YDykwRPzxs5f2N+X988CBXS7EQahDU+Vpet5QYMqLk+nsp+Qxw==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-wrap-function": "^7.16.0", + "@babel/helper-wrap-function": "^7.16.5", "@babel/types": "^7.16.0" } }, "@babel/helper-replace-supers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz", - "integrity": "sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.5.tgz", + "integrity": "sha512-ao3seGVa/FZCMCCNDuBcqnBFSbdr8N2EW35mzojx3TwfIbdPmNK+JV6+2d5bR0Z71W5ocLnQp9en/cTF7pBJiQ==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.16.0", + "@babel/helper-environment-visitor": "^7.16.5", + "@babel/helper-member-expression-to-functions": "^7.16.5", "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/traverse": "^7.16.0", + "@babel/traverse": "^7.16.5", "@babel/types": "^7.16.0" } }, @@ -23647,25 +23472,25 @@ "dev": true }, "@babel/helper-wrap-function": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz", - "integrity": "sha512-VVMGzYY3vkWgCJML+qVLvGIam902mJW0FvT7Avj1zEe0Gn7D93aWdLblYARTxEw+6DhZmtzhBM2zv0ekE5zg1g==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.5.tgz", + "integrity": "sha512-2J2pmLBqUqVdJw78U0KPNdeE2qeuIyKoG4mKV7wAq3mc4jJG282UgjZw4ZYDnqiWQuS3Y3IYdF/AQ6CpyBV3VA==", "dev": true, "requires": { "@babel/helper-function-name": "^7.16.0", "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", + "@babel/traverse": "^7.16.5", "@babel/types": "^7.16.0" } }, "@babel/helpers": { - "version": "7.16.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.3.tgz", - "integrity": "sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.5.tgz", + "integrity": "sha512-TLgi6Lh71vvMZGEkFuIxzaPsyeYCHQ5jJOOX1f0xXn0uciFuE8cEk0wyBquMcCxBXZ5BJhE2aUB7pnWTD150Tw==", "dev": true, "requires": { "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.3", + "@babel/traverse": "^7.16.5", "@babel/types": "^7.16.0" } }, @@ -23681,9 +23506,9 @@ } }, "@babel/parser": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.4.tgz", - "integrity": "sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng==", + "version": "7.16.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.6.tgz", + "integrity": "sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==", "dev": true }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { @@ -23707,161 +23532,161 @@ } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.4.tgz", - "integrity": "sha512-/CUekqaAaZCQHleSK/9HajvcD/zdnJiKRiuUFq8ITE+0HsPzquf53cpFiqAwl/UfmJbR6n5uGPQSPdrmKOvHHg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.5.tgz", + "integrity": "sha512-C/FX+3HNLV6sz7AqbTQqEo1L9/kfrKjxcVtgyBCmvIgOjvuBVUWooDoi7trsLxOzCEo5FccjRvKHkfDsJFZlfA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.16.4", + "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-remap-async-to-generator": "^7.16.5", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz", - "integrity": "sha512-mCF3HcuZSY9Fcx56Lbn+CGdT44ioBMMvjNVldpKtj8tpniETdLjnxdHI1+sDWXIM1nNt+EanJOZ3IG9lzVjs7A==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.5.tgz", + "integrity": "sha512-pJD3HjgRv83s5dv1sTnDbZOaTjghKEz8KUn1Kbh2eAIRhGuyQ1XSeI4xVXU3UlIEVA3DAyIdxqT1eRn7Wcn55A==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-proposal-class-static-block": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.0.tgz", - "integrity": "sha512-mAy3sdcY9sKAkf3lQbDiv3olOfiLqI51c9DR9b19uMoR2Z6r5pmGl7dfNFqEvqOyqbf1ta4lknK4gc5PJn3mfA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.5.tgz", + "integrity": "sha512-EEFzuLZcm/rNJ8Q5krK+FRKdVkd6FjfzT9tuSZql9sQn64K0hHA2KLJ0DqVot9/iV6+SsuadC5yI39zWnm+nmQ==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-create-class-features-plugin": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz", - "integrity": "sha512-QGSA6ExWk95jFQgwz5GQ2Dr95cf7eI7TKutIXXTb7B1gCLTCz5hTjFTQGfLFBBiC5WSNi7udNwWsqbbMh1c4yQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.5.tgz", + "integrity": "sha512-P05/SJZTTvHz79LNYTF8ff5xXge0kk5sIIWAypcWgX4BTRUgyHc8wRxJ/Hk+mU0KXldgOOslKaeqnhthcDJCJQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz", - "integrity": "sha512-CjI4nxM/D+5wCnhD11MHB1AwRSAYeDT+h8gCdcVJZ/OK7+wRzFsf7PFPWVpVpNRkHMmMkQWAHpTq+15IXQ1diA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.5.tgz", + "integrity": "sha512-i+sltzEShH1vsVydvNaTRsgvq2vZsfyrd7K7vPLUU/KgS0D5yZMe6uipM0+izminnkKrEfdUnz7CxMRb6oHZWw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz", - "integrity": "sha512-kouIPuiv8mSi5JkEhzApg5Gn6hFyKPnlkO0a9YSzqRurH8wYzSlf6RJdzluAsbqecdW5pBvDJDfyDIUR/vLxvg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.5.tgz", + "integrity": "sha512-QQJueTFa0y9E4qHANqIvMsuxM/qcLQmKttBACtPCQzGUEizsXDACGonlPiSwynHfOa3vNw0FPMVvQzbuXwh4SQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz", - "integrity": "sha512-pbW0fE30sVTYXXm9lpVQQ/Vc+iTeQKiXlaNRZPPN2A2VdlWyAtsUrsQ3xydSlDW00TFMK7a8m3cDTkBF5WnV3Q==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.5.tgz", + "integrity": "sha512-xqibl7ISO2vjuQM+MzR3rkd0zfNWltk7n9QhaD8ghMmMceVguYrNDt7MikRyj4J4v3QehpnrU8RYLnC7z/gZLA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz", - "integrity": "sha512-3bnHA8CAFm7cG93v8loghDYyQ8r97Qydf63BeYiGgYbjKKB/XP53W15wfRC7dvKfoiJ34f6Rbyyx2btExc8XsQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.5.tgz", + "integrity": "sha512-YwMsTp/oOviSBhrjwi0vzCUycseCYwoXnLiXIL3YNjHSMBHicGTz7GjVU/IGgz4DtOEXBdCNG72pvCX22ehfqg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz", - "integrity": "sha512-FAhE2I6mjispy+vwwd6xWPyEx3NYFS13pikDBWUAFGZvq6POGs5eNchw8+1CYoEgBl9n11I3NkzD7ghn25PQ9Q==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.5.tgz", + "integrity": "sha512-DvB9l/TcsCRvsIV9v4jxR/jVP45cslTVC0PMVHvaJhhNuhn2Y1SOhCSFlPK777qLB5wb8rVDaNoqMTyOqtY5Iw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz", - "integrity": "sha512-LU/+jp89efe5HuWJLmMmFG0+xbz+I2rSI7iLc1AlaeSMDMOGzWlc5yJrMN1d04osXN4sSfpo4O+azkBNBes0jg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.5.tgz", + "integrity": "sha512-UEd6KpChoyPhCoE840KRHOlGhEZFutdPDMGj+0I56yuTTOaT51GzmnEl/0uT41fB/vD2nT+Pci2KjezyE3HmUw==", "dev": true, "requires": { - "@babel/compat-data": "^7.16.0", - "@babel/helper-compilation-targets": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/compat-data": "^7.16.4", + "@babel/helper-compilation-targets": "^7.16.3", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.0" + "@babel/plugin-transform-parameters": "^7.16.5" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz", - "integrity": "sha512-kicDo0A/5J0nrsCPbn89mTG3Bm4XgYi0CZtvex9Oyw7gGZE3HXGD0zpQNH+mo+tEfbo8wbmMvJftOwpmPy7aVw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.5.tgz", + "integrity": "sha512-ihCMxY1Iljmx4bWy/PIMJGXN4NS4oUj1MKynwO07kiKms23pNvIn1DMB92DNB2R0EA882sw0VXIelYGdtF7xEQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz", - "integrity": "sha512-Y4rFpkZODfHrVo70Uaj6cC1JJOt3Pp0MdWSwIKtb8z1/lsjl9AmnB7ErRFV+QNGIfcY1Eruc2UMx5KaRnXjMyg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.5.tgz", + "integrity": "sha512-kzdHgnaXRonttiTfKYnSVafbWngPPr2qKw9BWYBESl91W54e+9R5pP70LtWxV56g0f05f/SQrwHYkfvbwcdQ/A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-private-methods": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz", - "integrity": "sha512-IvHmcTHDFztQGnn6aWq4t12QaBXTKr1whF/dgp9kz84X6GUcwq9utj7z2wFCUfeOup/QKnOlt2k0zxkGFx9ubg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.5.tgz", + "integrity": "sha512-+yFMO4BGT3sgzXo+lrq7orX5mAZt57DwUK6seqII6AcJnJOIhBJ8pzKH47/ql/d426uQ7YhN8DpUFirQzqYSUA==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.0.tgz", - "integrity": "sha512-3jQUr/HBbMVZmi72LpjQwlZ55i1queL8KcDTQEkAHihttJnAPrcvG9ZNXIfsd2ugpizZo595egYV6xy+pv4Ofw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.5.tgz", + "integrity": "sha512-+YGh5Wbw0NH3y/E5YMu6ci5qTDmAEVNoZ3I54aB6nVEOZ5BQ7QJlwKq5pYVucQilMByGn/bvX0af+uNaPRCabA==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-create-class-features-plugin": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz", - "integrity": "sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.5.tgz", + "integrity": "sha512-s5sKtlKQyFSatt781HQwv1hoM5BQ9qRH30r+dK56OLDsHmV74mzwJNX7R1yMuE7VZKG5O6q/gmOGSAO6ikTudg==", "dev": true, "requires": { "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-syntax-async-generators": { @@ -24000,232 +23825,233 @@ } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz", - "integrity": "sha512-vIFb5250Rbh7roWARvCLvIJ/PtAU5Lhv7BtZ1u24COwpI9Ypjsh+bZcKk6rlIyalK+r0jOc1XQ8I4ovNxNrWrA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.5.tgz", + "integrity": "sha512-8bTHiiZyMOyfZFULjsCnYOWG059FVMes0iljEHSfARhNgFfpsqE92OrCffv3veSw9rwMkYcFe9bj0ZoXU2IGtQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz", - "integrity": "sha512-PbIr7G9kR8tdH6g8Wouir5uVjklETk91GMVSUq+VaOgiinbCkBP6Q7NN/suM/QutZkMJMvcyAriogcYAdhg8Gw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.5.tgz", + "integrity": "sha512-TMXgfioJnkXU+XRoj7P2ED7rUm5jbnDWwlCuFVTpQboMfbSya5WrmubNBAMlk7KXvywpo8rd8WuYZkis1o2H8w==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.16.0" + "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-remap-async-to-generator": "^7.16.5" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz", - "integrity": "sha512-V14As3haUOP4ZWrLJ3VVx5rCnrYhMSHN/jX7z6FAt5hjRkLsb0snPCmJwSOML5oxkKO4FNoNv7V5hw/y2bjuvg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.5.tgz", + "integrity": "sha512-BxmIyKLjUGksJ99+hJyL/HIxLIGnLKtw772zYDER7UuycDZ+Xvzs98ZQw6NGgM2ss4/hlFAaGiZmMNKvValEjw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz", - "integrity": "sha512-27n3l67/R3UrXfizlvHGuTwsRIFyce3D/6a37GRxn28iyTPvNXaW4XvznexRh1zUNLPjbLL22Id0XQElV94ruw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.5.tgz", + "integrity": "sha512-JxjSPNZSiOtmxjX7PBRBeRJTUKTyJ607YUYeT0QJCNdsedOe+/rXITjP08eG8xUpsLfPirgzdCFN+h0w6RI+pQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-classes": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz", - "integrity": "sha512-HUxMvy6GtAdd+GKBNYDWCIA776byUQH8zjnfjxwT1P1ARv/wFu8eBDpmXQcLS/IwRtrxIReGiplOwMeyO7nsDQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.5.tgz", + "integrity": "sha512-DzJ1vYf/7TaCYy57J3SJ9rV+JEuvmlnvvyvYKFbk5u46oQbBvuB9/0w+YsVsxkOv8zVWKpDmUoj4T5ILHoXevA==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.16.0", + "@babel/helper-environment-visitor": "^7.16.5", "@babel/helper-function-name": "^7.16.0", "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.16.0", + "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-replace-supers": "^7.16.5", "@babel/helper-split-export-declaration": "^7.16.0", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz", - "integrity": "sha512-63l1dRXday6S8V3WFY5mXJwcRAnPYxvFfTlt67bwV1rTyVTM5zrp0DBBb13Kl7+ehkCVwIZPumPpFP/4u70+Tw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.5.tgz", + "integrity": "sha512-n1+O7xtU5lSLraRzX88CNcpl7vtGdPakKzww74bVwpAIRgz9JVLJJpOLb0uYqcOaXVM0TL6X0RVeIJGD2CnCkg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-destructuring": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz", - "integrity": "sha512-Q7tBUwjxLTsHEoqktemHBMtb3NYwyJPTJdM+wDwb0g8PZ3kQUIzNvwD5lPaqW/p54TXBc/MXZu9Jr7tbUEUM8Q==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.5.tgz", + "integrity": "sha512-GuRVAsjq+c9YPK6NeTkRLWyQskDC099XkBSVO+6QzbnOnH2d/4mBVXYStaPrZD3dFRfg00I6BFJ9Atsjfs8mlg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz", - "integrity": "sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.5.tgz", + "integrity": "sha512-iQiEMt8Q4/5aRGHpGVK2Zc7a6mx7qEAO7qehgSug3SDImnuMzgmm/wtJALXaz25zUj1PmnNHtShjFgk4PDx4nw==", "dev": true, "requires": { "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz", - "integrity": "sha512-LIe2kcHKAZOJDNxujvmp6z3mfN6V9lJxubU4fJIGoQCkKe3Ec2OcbdlYP+vW++4MpxwG0d1wSDOJtQW5kLnkZQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.5.tgz", + "integrity": "sha512-81tijpDg2a6I1Yhj4aWY1l3O1J4Cg/Pd7LfvuaH2VVInAkXtzibz9+zSPdUM1WvuUi128ksstAP0hM5w48vQgg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz", - "integrity": "sha512-OwYEvzFI38hXklsrbNivzpO3fh87skzx8Pnqi4LoSYeav0xHlueSoCJrSgTPfnbyzopo5b3YVAJkFIcUpK2wsw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.5.tgz", + "integrity": "sha512-12rba2HwemQPa7BLIKCzm1pT2/RuQHtSFHdNl41cFiC6oi4tcrp7gjB07pxQvFpcADojQywSjblQth6gJyE6CA==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-for-of": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz", - "integrity": "sha512-5QKUw2kO+GVmKr2wMYSATCTTnHyscl6sxFRAY+rvN7h7WB0lcG0o4NoV6ZQU32OZGVsYUsfLGgPQpDFdkfjlJQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.5.tgz", + "integrity": "sha512-+DpCAJFPAvViR17PIMi9x2AE34dll5wNlXO43wagAX2YcRGgEVHCNFC4azG85b4YyyFarvkc/iD5NPrz4Oneqw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-function-name": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz", - "integrity": "sha512-lBzMle9jcOXtSOXUpc7tvvTpENu/NuekNJVova5lCCWCV9/U1ho2HH2y0p6mBg8fPm/syEAbfaaemYGOHCY3mg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.5.tgz", + "integrity": "sha512-Fuec/KPSpVLbGo6z1RPw4EE1X+z9gZk1uQmnYy7v4xr4TO9p41v1AoUuXEtyqAI7H+xNJYSICzRqZBhDEkd3kQ==", "dev": true, "requires": { "@babel/helper-function-name": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz", - "integrity": "sha512-gQDlsSF1iv9RU04clgXqRjrPyyoJMTclFt3K1cjLmTKikc0s/6vE3hlDeEVC71wLTRu72Fq7650kABrdTc2wMQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.5.tgz", + "integrity": "sha512-B1j9C/IfvshnPcklsc93AVLTrNVa69iSqztylZH6qnmiAsDDOmmjEYqOm3Ts2lGSgTSywnBNiqC949VdD0/gfw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz", - "integrity": "sha512-WRpw5HL4Jhnxw8QARzRvwojp9MIE7Tdk3ez6vRyUk1MwgjJN0aNpRoXainLR5SgxmoXx/vsXGZ6OthP6t/RbUg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.5.tgz", + "integrity": "sha512-d57i3vPHWgIde/9Y8W/xSFUndhvhZN5Wu2TjRrN1MVz5KzdUihKnfDVlfP1U7mS5DNj/WHHhaE4/tTi4hIyHwQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz", - "integrity": "sha512-rWFhWbCJ9Wdmzln1NmSCqn7P0RAD+ogXG/bd9Kg5c7PKWkJtkiXmYsMBeXjDlzHpVTJ4I/hnjs45zX4dEv81xw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.5.tgz", + "integrity": "sha512-oHI15S/hdJuSCfnwIz+4lm6wu/wBn7oJ8+QrkzPPwSFGXk8kgdI/AIKcbR/XnD1nQVMg/i6eNaXpszbGuwYDRQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-module-transforms": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz", - "integrity": "sha512-Dzi+NWqyEotgzk/sb7kgQPJQf7AJkQBWsVp1N6JWc1lBVo0vkElUnGdr1PzUBmfsCCN5OOFya3RtpeHk15oLKQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.5.tgz", + "integrity": "sha512-ABhUkxvoQyqhCWyb8xXtfwqNMJD7tx+irIRnUh6lmyFud7Jln1WzONXKlax1fg/ey178EXbs4bSGNd6PngO+SQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-module-transforms": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/helper-simple-access": "^7.16.0", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz", - "integrity": "sha512-yuGBaHS3lF1m/5R+6fjIke64ii5luRUg97N2wr+z1sF0V+sNSXPxXDdEEL/iYLszsN5VKxVB1IPfEqhzVpiqvg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.5.tgz", + "integrity": "sha512-53gmLdScNN28XpjEVIm7LbWnD/b/TpbwKbLk6KV4KqC9WyU6rq1jnNmVG6UgAdQZVVGZVoik3DqHNxk4/EvrjA==", "dev": true, "requires": { "@babel/helper-hoist-variables": "^7.16.0", - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-module-transforms": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/helper-validator-identifier": "^7.15.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz", - "integrity": "sha512-nx4f6no57himWiHhxDM5pjwhae5vLpTK2zCnDH8+wNLJy0TVER/LJRHl2bkt6w9Aad2sPD5iNNoUpY3X9sTGDg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.5.tgz", + "integrity": "sha512-qTFnpxHMoenNHkS3VoWRdwrcJ3FhX567GvDA3hRZKF0Dj8Fmg0UzySZp3AP2mShl/bzcywb/UWAMQIjA1bhXvw==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-module-transforms": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz", - "integrity": "sha512-LogN88uO+7EhxWc8WZuQ8vxdSyVGxhkh8WTC3tzlT8LccMuQdA81e9SGV6zY7kY2LjDhhDOFdQVxdGwPyBCnvg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.5.tgz", + "integrity": "sha512-/wqGDgvFUeKELW6ex6QB7dLVRkd5ehjw34tpXu1nhKC0sFfmaLabIswnpf8JgDyV2NeDmZiwoOb0rAmxciNfjA==", "dev": true, "requires": { "@babel/helper-create-regexp-features-plugin": "^7.16.0" } }, "@babel/plugin-transform-new-target": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz", - "integrity": "sha512-fhjrDEYv2DBsGN/P6rlqakwRwIp7rBGLPbrKxwh7oVt5NNkIhZVOY2GRV+ULLsQri1bDqwDWnU3vhlmx5B2aCw==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.5.tgz", + "integrity": "sha512-ZaIrnXF08ZC8jnKR4/5g7YakGVL6go6V9ql6Jl3ecO8PQaQqFE74CuM384kezju7Z9nGCCA20BqZaR1tJ/WvHg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-object-super": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz", - "integrity": "sha512-fds+puedQHn4cPLshoHcR1DTMN0q1V9ou0mUjm8whx9pGcNvDrVVrgw+KJzzCaiTdaYhldtrUps8DWVMgrSEyg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.5.tgz", + "integrity": "sha512-tded+yZEXuxt9Jdtkc1RraW1zMF/GalVxaVVxh41IYwirdRgyAxxxCKZ9XB7LxZqmsjfjALxupNE1MIz9KH+Zg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.16.0" + "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-replace-supers": "^7.16.5" } }, "@babel/plugin-transform-parameters": { - "version": "7.16.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.3.tgz", - "integrity": "sha512-3MaDpJrOXT1MZ/WCmkOFo7EtmVVC8H4EUZVrHvFOsmwkk4lOjQj8rzv8JKUZV4YoQKeoIgk07GO+acPU9IMu/w==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.5.tgz", + "integrity": "sha512-B3O6AL5oPop1jAVg8CV+haeUte9oFuY85zu0jwnRNZZi3tVAbJriu5tag/oaO2kGaQM/7q7aGPBlTI5/sr9enA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-property-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz", - "integrity": "sha512-XLldD4V8+pOqX2hwfWhgwXzGdnDOThxaNTgqagOcpBgIxbUvpgU2FMvo5E1RyHbk756WYgdbS0T8y0Cj9FKkWQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.5.tgz", + "integrity": "sha512-+IRcVW71VdF9pEH/2R/Apab4a19LVvdVsr/gEeotH00vSDVlKD+XgfSIw+cgGWsjDB/ziqGv/pGoQZBIiQVXHg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-react-display-name": { @@ -24288,86 +24114,86 @@ } }, "@babel/plugin-transform-regenerator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz", - "integrity": "sha512-JAvGxgKuwS2PihiSFaDrp94XOzzTUeDeOQlcKzVAyaPap7BnZXK/lvMDiubkPTdotPKOIZq9xWXWnggUMYiExg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.5.tgz", + "integrity": "sha512-2z+it2eVWU8TtQQRauvGUqZwLy4+7rTfo6wO4npr+fvvN1SW30ZF3O/ZRCNmTuu4F5MIP8OJhXAhRV5QMJOuYg==", "dev": true, "requires": { "regenerator-transform": "^0.14.2" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz", - "integrity": "sha512-Dgs8NNCehHSvXdhEhln8u/TtJxfVwGYCgP2OOr5Z3Ar+B+zXicEOKNTyc+eca2cuEOMtjW6m9P9ijOt8QdqWkg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.5.tgz", + "integrity": "sha512-aIB16u8lNcf7drkhXJRoggOxSTUAuihTSTfAcpynowGJOZiGf+Yvi7RuTwFzVYSYPmWyARsPqUGoZWWWxLiknw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz", - "integrity": "sha512-iVb1mTcD8fuhSv3k99+5tlXu5N0v8/DPm2mO3WACLG6al1CGZH7v09HJyUb1TtYl/Z+KrM6pHSIJdZxP5A+xow==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.5.tgz", + "integrity": "sha512-ZbuWVcY+MAXJuuW7qDoCwoxDUNClfZxoo7/4swVbOW1s/qYLOMHlm9YRWMsxMFuLs44eXsv4op1vAaBaBaDMVg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-spread": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz", - "integrity": "sha512-Ao4MSYRaLAQczZVp9/7E7QHsCuK92yHRrmVNRe/SlEJjhzivq0BSn8mEraimL8wizHZ3fuaHxKH0iwzI13GyGg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.5.tgz", + "integrity": "sha512-5d6l/cnG7Lw4tGHEoga4xSkYp1euP7LAtrah1h1PgJ3JY7yNsjybsxQAnVK4JbtReZ/8z6ASVmd3QhYYKLaKZw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz", - "integrity": "sha512-/ntT2NljR9foobKk4E/YyOSwcGUXtYWv5tinMK/3RkypyNBNdhHUaq6Orw5DWq9ZcNlS03BIlEALFeQgeVAo4Q==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.5.tgz", + "integrity": "sha512-usYsuO1ID2LXxzuUxifgWtJemP7wL2uZtyrTVM4PKqsmJycdS4U4mGovL5xXkfUheds10Dd2PjoQLXw6zCsCbg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-template-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz", - "integrity": "sha512-Rd4Ic89hA/f7xUSJQk5PnC+4so50vBoBfxjdQAdvngwidM8jYIBVxBZ/sARxD4e0yMXRbJVDrYf7dyRtIIKT6Q==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.5.tgz", + "integrity": "sha512-gnyKy9RyFhkovex4BjKWL3BVYzUDG6zC0gba7VMLbQoDuqMfJ1SDXs8k/XK41Mmt1Hyp4qNAvGFb9hKzdCqBRQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz", - "integrity": "sha512-++V2L8Bdf4vcaHi2raILnptTBjGEFxn5315YU+e8+EqXIucA+q349qWngCLpUYqqv233suJ6NOienIVUpS9cqg==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.5.tgz", + "integrity": "sha512-ldxCkW180qbrvyCVDzAUZqB0TAeF8W/vGJoRcaf75awm6By+PxfJKvuqVAnq8N9wz5Xa6mSpM19OfVKKVmGHSQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz", - "integrity": "sha512-VFi4dhgJM7Bpk8lRc5CMaRGlKZ29W9C3geZjt9beuzSUrlJxsNwX7ReLwaL6WEvsOf2EQkyIJEPtF8EXjB/g2A==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.5.tgz", + "integrity": "sha512-shiCBHTIIChGLdyojsKQjoAyB8MBwat25lKM7MJjbe1hE0bgIppD+LX9afr41lLHOhqceqeWl4FkLp+Bgn9o1Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz", - "integrity": "sha512-jHLK4LxhHjvCeZDWyA9c+P9XH1sOxRd1RO9xMtDVRAOND/PczPqizEtVdx4TQF/wyPaewqpT+tgQFYMnN/P94A==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.5.tgz", + "integrity": "sha512-GTJ4IW012tiPEMMubd7sD07iU9O/LOo8Q/oU4xNhcaq0Xn8+6TcUQaHtC8YxySo1T+ErQ8RaWogIEeFhKGNPzw==", "dev": true, "requires": { "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.5" } }, "@babel/polyfill": { @@ -24387,32 +24213,32 @@ } }, "@babel/preset-env": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.4.tgz", - "integrity": "sha512-v0QtNd81v/xKj4gNKeuAerQ/azeNn/G1B1qMLeXOcV8+4TWlD2j3NV1u8q29SDFBXx/NBq5kyEAO+0mpRgacjA==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.5.tgz", + "integrity": "sha512-MiJJW5pwsktG61NDxpZ4oJ1CKxM1ncam9bzRtx9g40/WkLRkxFP6mhpkYV0/DxcciqoiHicx291+eUQrXb/SfQ==", "dev": true, "requires": { "@babel/compat-data": "^7.16.4", "@babel/helper-compilation-targets": "^7.16.3", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.5", "@babel/helper-validator-option": "^7.14.5", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.2", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-async-generator-functions": "^7.16.4", - "@babel/plugin-proposal-class-properties": "^7.16.0", - "@babel/plugin-proposal-class-static-block": "^7.16.0", - "@babel/plugin-proposal-dynamic-import": "^7.16.0", - "@babel/plugin-proposal-export-namespace-from": "^7.16.0", - "@babel/plugin-proposal-json-strings": "^7.16.0", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", - "@babel/plugin-proposal-numeric-separator": "^7.16.0", - "@babel/plugin-proposal-object-rest-spread": "^7.16.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-private-methods": "^7.16.0", - "@babel/plugin-proposal-private-property-in-object": "^7.16.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.0", + "@babel/plugin-proposal-async-generator-functions": "^7.16.5", + "@babel/plugin-proposal-class-properties": "^7.16.5", + "@babel/plugin-proposal-class-static-block": "^7.16.5", + "@babel/plugin-proposal-dynamic-import": "^7.16.5", + "@babel/plugin-proposal-export-namespace-from": "^7.16.5", + "@babel/plugin-proposal-json-strings": "^7.16.5", + "@babel/plugin-proposal-logical-assignment-operators": "^7.16.5", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.5", + "@babel/plugin-proposal-numeric-separator": "^7.16.5", + "@babel/plugin-proposal-object-rest-spread": "^7.16.5", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.5", + "@babel/plugin-proposal-optional-chaining": "^7.16.5", + "@babel/plugin-proposal-private-methods": "^7.16.5", + "@babel/plugin-proposal-private-property-in-object": "^7.16.5", + "@babel/plugin-proposal-unicode-property-regex": "^7.16.5", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", @@ -24427,38 +24253,38 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.0", - "@babel/plugin-transform-async-to-generator": "^7.16.0", - "@babel/plugin-transform-block-scoped-functions": "^7.16.0", - "@babel/plugin-transform-block-scoping": "^7.16.0", - "@babel/plugin-transform-classes": "^7.16.0", - "@babel/plugin-transform-computed-properties": "^7.16.0", - "@babel/plugin-transform-destructuring": "^7.16.0", - "@babel/plugin-transform-dotall-regex": "^7.16.0", - "@babel/plugin-transform-duplicate-keys": "^7.16.0", - "@babel/plugin-transform-exponentiation-operator": "^7.16.0", - "@babel/plugin-transform-for-of": "^7.16.0", - "@babel/plugin-transform-function-name": "^7.16.0", - "@babel/plugin-transform-literals": "^7.16.0", - "@babel/plugin-transform-member-expression-literals": "^7.16.0", - "@babel/plugin-transform-modules-amd": "^7.16.0", - "@babel/plugin-transform-modules-commonjs": "^7.16.0", - "@babel/plugin-transform-modules-systemjs": "^7.16.0", - "@babel/plugin-transform-modules-umd": "^7.16.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.0", - "@babel/plugin-transform-new-target": "^7.16.0", - "@babel/plugin-transform-object-super": "^7.16.0", - "@babel/plugin-transform-parameters": "^7.16.3", - "@babel/plugin-transform-property-literals": "^7.16.0", - "@babel/plugin-transform-regenerator": "^7.16.0", - "@babel/plugin-transform-reserved-words": "^7.16.0", - "@babel/plugin-transform-shorthand-properties": "^7.16.0", - "@babel/plugin-transform-spread": "^7.16.0", - "@babel/plugin-transform-sticky-regex": "^7.16.0", - "@babel/plugin-transform-template-literals": "^7.16.0", - "@babel/plugin-transform-typeof-symbol": "^7.16.0", - "@babel/plugin-transform-unicode-escapes": "^7.16.0", - "@babel/plugin-transform-unicode-regex": "^7.16.0", + "@babel/plugin-transform-arrow-functions": "^7.16.5", + "@babel/plugin-transform-async-to-generator": "^7.16.5", + "@babel/plugin-transform-block-scoped-functions": "^7.16.5", + "@babel/plugin-transform-block-scoping": "^7.16.5", + "@babel/plugin-transform-classes": "^7.16.5", + "@babel/plugin-transform-computed-properties": "^7.16.5", + "@babel/plugin-transform-destructuring": "^7.16.5", + "@babel/plugin-transform-dotall-regex": "^7.16.5", + "@babel/plugin-transform-duplicate-keys": "^7.16.5", + "@babel/plugin-transform-exponentiation-operator": "^7.16.5", + "@babel/plugin-transform-for-of": "^7.16.5", + "@babel/plugin-transform-function-name": "^7.16.5", + "@babel/plugin-transform-literals": "^7.16.5", + "@babel/plugin-transform-member-expression-literals": "^7.16.5", + "@babel/plugin-transform-modules-amd": "^7.16.5", + "@babel/plugin-transform-modules-commonjs": "^7.16.5", + "@babel/plugin-transform-modules-systemjs": "^7.16.5", + "@babel/plugin-transform-modules-umd": "^7.16.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.5", + "@babel/plugin-transform-new-target": "^7.16.5", + "@babel/plugin-transform-object-super": "^7.16.5", + "@babel/plugin-transform-parameters": "^7.16.5", + "@babel/plugin-transform-property-literals": "^7.16.5", + "@babel/plugin-transform-regenerator": "^7.16.5", + "@babel/plugin-transform-reserved-words": "^7.16.5", + "@babel/plugin-transform-shorthand-properties": "^7.16.5", + "@babel/plugin-transform-spread": "^7.16.5", + "@babel/plugin-transform-sticky-regex": "^7.16.5", + "@babel/plugin-transform-template-literals": "^7.16.5", + "@babel/plugin-transform-typeof-symbol": "^7.16.5", + "@babel/plugin-transform-unicode-escapes": "^7.16.5", + "@babel/plugin-transform-unicode-regex": "^7.16.5", "@babel/preset-modules": "^0.1.5", "@babel/types": "^7.16.0", "babel-plugin-polyfill-corejs2": "^0.3.0", @@ -24490,9 +24316,9 @@ } }, "@babel/register": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.16.0.tgz", - "integrity": "sha512-lzl4yfs0zVXnooeLE0AAfYaT7F3SPA8yB2Bj4W1BiZwLbMS3MZH35ZvCWSRHvneUugwuM+Wsnrj7h0F7UmU3NQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.16.5.tgz", + "integrity": "sha512-NpluD+cToBiZiDsG3y9rtIcqDyivsahpaM9csfyfiq1qQWduSmihUZ+ruIqqSDGjZKZMJfgAElo9x2YWlOQuRw==", "dev": true, "requires": { "clone-deep": "^4.0.1", @@ -24511,9 +24337,9 @@ } }, "@babel/runtime-corejs3": { - "version": "7.16.3", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.3.tgz", - "integrity": "sha512-IAdDC7T0+wEB4y2gbIL0uOXEYpiZEeuFUTVbdGq+UwCcF35T/tS8KrmMomEwEc5wBbyfH3PJVpTSUqrhPDXFcQ==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.5.tgz", + "integrity": "sha512-F1pMwvTiUNSAM8mc45kccMQxj31x3y3P+tA/X8hKNWp3/hUsxdGxZ3D3H8JIkxtfA8qGkaBTKvcmvStaYseAFw==", "dev": true, "requires": { "core-js-pure": "^3.19.0", @@ -24532,17 +24358,18 @@ } }, "@babel/traverse": { - "version": "7.16.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.3.tgz", - "integrity": "sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==", + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.5.tgz", + "integrity": "sha512-FOCODAzqUMROikDYLYxl4nmwiLlu85rNqBML/A5hKRVXG2LV8d0iMqgPzdYTcIpjZEBB7D6UDU9vxRZiriASdQ==", "dev": true, "requires": { "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.0", + "@babel/generator": "^7.16.5", + "@babel/helper-environment-visitor": "^7.16.5", "@babel/helper-function-name": "^7.16.0", "@babel/helper-hoist-variables": "^7.16.0", "@babel/helper-split-export-declaration": "^7.16.0", - "@babel/parser": "^7.16.3", + "@babel/parser": "^7.16.5", "@babel/types": "^7.16.0", "debug": "^4.1.0", "globals": "^11.1.0" @@ -25414,61 +25241,40 @@ } } }, - "@es-joy/jsdoccomment": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.13.0.tgz", - "integrity": "sha512-APVqbVPGOprb4BmjEnwbSzV+V2e/6DVIUnZG3zdW5uWXWkN0DKMCpiIy2TdBauoANKYO7RQpO8cTjIYNVSKwUA==", - "dev": true, - "requires": { - "comment-parser": "1.3.0", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "2.0.0" - } - }, "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", + "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.1.1", "espree": "^7.3.0", - "globals": "^13.9.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, "dependencies": { "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "requires": { "ms": "2.1.2" } }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - } - }, "globals": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", - "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", "dev": true, "requires": { - "type-fest": "^0.20.2" + "type-fest": "^0.8.1" } }, "ignore": { @@ -25477,48 +25283,14 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true } } }, - "@fintechstudios/eslint-plugin-chai-as-promised": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@fintechstudios/eslint-plugin-chai-as-promised/-/eslint-plugin-chai-as-promised-3.1.0.tgz", - "integrity": "sha512-Y3TmITTwc5u8hoW0GWxle1hKiVadDqDHyLQaTv+e+xVDHazn361QIEY9NbWqNsXP0jzrSskpnhkBr++h+PciEw==", - "dev": true - }, "@hapi/hoek": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz", @@ -25534,40 +25306,6 @@ "@hapi/hoek": "^9.0.0" } }, - "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "dependencies": { - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", - "dev": true - }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -26013,12 +25751,6 @@ "regenerator-runtime": "^0.13.3" } }, - "@mdn/browser-compat-data": { - "version": "3.3.14", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-3.3.14.tgz", - "integrity": "sha512-n2RC9d6XatVbWFdHLimzzUJxJ1KY8LdjqrW6YvGPiRmsHkhOUx74/Ct10x5Yo7bC/Jvqx7cDEW8IMPv/+vwEzA==", - "dev": true - }, "@nodelib/fs.scandir": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", @@ -26212,9 +25944,9 @@ } }, "@rollup/plugin-node-resolve": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.6.tgz", - "integrity": "sha512-sFsPDMPd4gMqnh2gS0uIxELnoRUp5kBl5knxD2EO0778G1oOJv4G1vyT2cpWz75OU2jDVcXhjVUuTAczGyFNKA==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.1.tgz", + "integrity": "sha512-6QKtRevXLrmEig9UiMYt2fSvee9TyltGRfw+qSs6xjUnxwjOzTOqy+/Lpxsgjb8mJn1EQNbCDAvt89O4uzL5kw==", "dev": true, "requires": { "@rollup/pluginutils": "^3.1.0", @@ -26910,33 +26642,6 @@ } } }, - "@web/dev-server-esbuild": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/@web/dev-server-esbuild/-/dev-server-esbuild-0.2.16.tgz", - "integrity": "sha512-a82uKy9vQ4HvfWtjd7hJ3GtaqkL2ofxpEu3a1wIZyXB2dFWPvhRSmLNe/4IPPHe4vj6PVdRpLSFPEA3lXUW5Pw==", - "dev": true, - "requires": { - "@mdn/browser-compat-data": "^4.0.0", - "@web/dev-server-core": "^0.3.17", - "esbuild": "^0.12.21", - "parse5": "^6.0.1", - "ua-parser-js": "^1.0.2" - }, - "dependencies": { - "@mdn/browser-compat-data": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-4.1.0.tgz", - "integrity": "sha512-58eB5/ovJ5CfArzZwmZdenF/WlAGGS+1PG8RUb3oJ4st9exETBjClmFC0E1uVrZG1BwPaT205RKS8RhnUh5x3Q==", - "dev": true - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - } - } - }, "@web/dev-server-rollup": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@web/dev-server-rollup/-/dev-server-rollup-0.3.13.tgz", @@ -27061,9 +26766,9 @@ } }, "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "requires": {} }, @@ -27239,9 +26944,9 @@ } }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { @@ -27392,6 +27097,17 @@ "es-abstract": "^1.19.0" } }, + "array.prototype.flatmap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", + "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + } + }, "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", @@ -27472,15 +27188,6 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, - "ast-metadata-inferer": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.7.0.tgz", - "integrity": "sha512-OkMLzd8xelb3gmnp6ToFvvsHLtS6CbagTkFQvQ+ZYFe3/AIl9iKikNR9G7pY3GfOR/2Xc222hwBjzI7HLkE76Q==", - "dev": true, - "requires": { - "@mdn/browser-compat-data": "^3.3.14" - } - }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -28613,12 +28320,6 @@ "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "dev": true }, - "comment-parser": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.0.tgz", - "integrity": "sha512-hRpmWIKgzd81vn0ydoWoyPoALEOnF4wt8yKD35Ib1D6XC2siLiYaiqfGkYrunuKdsXGwpBpHU3+9r+RVw2NZfA==", - "dev": true - }, "common-tags": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", @@ -28836,14 +28537,14 @@ } }, "core-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.3.tgz", - "integrity": "sha512-LeLBMgEGSsG7giquSzvgBrTS7V5UL6ks3eQlUSbN8dJStlLFiRzUm5iqsRyzUB8carhfKjkJ2vzKqE6z1Vga9g==" + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.1.tgz", + "integrity": "sha512-btdpStYFQScnNVQ5slVcr858KP0YWYjV16eGJQw8Gg7CWtu/2qNvIM3qVRIR3n1pK2R9NNOrTevbvAYxajwEjg==" }, "core-js-bundle": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/core-js-bundle/-/core-js-bundle-3.19.3.tgz", - "integrity": "sha512-mzXBG3MkmPpBEVAPCIPx9QAle9mEkuZyuMv7Zivp0bgTG/b9BOZ7rTibYomh9zR0dKc6bM8yyco0zaLuZAv9bQ==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/core-js-bundle/-/core-js-bundle-3.20.1.tgz", + "integrity": "sha512-WP0sI7ge37iSWwaQmGIL2mtGvJah/KgC9FzAz0CZljXJqqZxvr8enzdjuxsoZ6jTr/Ya6MvDc0sKECUkLI/Nmw==", "dev": true }, "core-js-compat": { @@ -29163,9 +28864,9 @@ } }, "cypress": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.1.1.tgz", - "integrity": "sha512-yWcYD8SEQ8F3okFbRPqSDj5V0xhrZBT5QRIH+P1J2vYvtEmZ4KGciHE7LCcZZLILOrs7pg4WNCqkj/XRvReQlQ==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.2.0.tgz", + "integrity": "sha512-Jn26Tprhfzh/a66Sdj9SoaYlnNX6Mjfmj5PHu2a7l3YHXhrgmavM368wjCmgrxC6KHTOv9SpMQGhAJn+upDViA==", "dev": true, "requires": { "@cypress/request": "^2.88.10", @@ -29710,17 +29411,6 @@ "esutils": "^2.0.2" } }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, "dom-walk": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", @@ -29733,12 +29423,6 @@ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - }, "domexception": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", @@ -29756,32 +29440,12 @@ } } }, - "domhandler": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", - "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", - "dev": true, - "requires": { - "domelementtype": "^2.2.0" - } - }, "dompurify": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.2.6.tgz", "integrity": "sha512-7b7ZArhhH0SP6W2R9cqK6RjaU82FZ2UPM7RO8qN1b1wyvC/NY1FNWcX1Pu00fFOAnzEORtwXe4bPaClg6pUybQ==", "devOptional": true }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -30074,12 +29738,6 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, - "esbuild": { - "version": "0.12.29", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.29.tgz", - "integrity": "sha512-w/XuoBCSwepyiZtIRsKsetiLDUVGPVw1E/R3VTFSecIy8UR7Cq3SOtwKHJMFoVqqVG36aGkzh4e8BvpO1Fdc7g==", - "dev": true - }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -30121,32 +29779,29 @@ } }, "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz", + "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==", "dev": true, "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.3.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.0.1", "doctrine": "^3.0.0", "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", "eslint-scope": "^5.1.1", "eslint-utils": "^2.1.0", "eslint-visitor-keys": "^2.0.0", "espree": "^7.3.1", - "esquery": "^1.4.0", + "esquery": "^1.2.0", "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^6.0.0", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -30154,7 +29809,7 @@ "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash.merge": "^4.6.2", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", @@ -30163,20 +29818,11 @@ "semver": "^7.2.1", "strip-ansi": "^6.0.0", "strip-json-comments": "^3.1.0", - "table": "^6.0.9", + "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -30212,89 +29858,20 @@ "dev": true }, "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "requires": { "ms": "2.1.2" } }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, "glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -30305,12 +29882,12 @@ } }, "globals": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.6.0.tgz", - "integrity": "sha512-YFKCX0SiPg7l5oKYCJ2zZGxcXprVXHcSnVuvzrT3oSENQonVLqM5pf9fN5dLGZGyCjhw8TN8Btwe/jKnZ0pjvQ==", + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", "dev": true, "requires": { - "type-fest": "^0.20.2" + "type-fest": "^0.8.1" } }, "has-flag": { @@ -30325,16 +29902,6 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -30371,18 +29938,6 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, "semver": { "version": "7.3.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", @@ -30392,12 +29947,6 @@ "lru-cache": "^6.0.0" } }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -30415,12 +29964,6 @@ "requires": { "prelude-ls": "^1.2.1" } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true } } }, @@ -30431,6 +29974,13 @@ "dev": true, "requires": {} }, + "eslint-config-standard-jsx": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-10.0.0.tgz", + "integrity": "sha512-hLeA2f5e06W1xyr/93/QJulN/rLbUVUmqTlexv9PRKHFwEC9ffJcH2LvJhMoEqYQBEYafedgGZXH2W8NUpt5lA==", + "dev": true, + "requires": {} + }, "eslint-import-resolver-node": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", @@ -30538,141 +30088,12 @@ } } }, - "eslint-plugin-array-func": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/eslint-plugin-array-func/-/eslint-plugin-array-func-3.1.7.tgz", - "integrity": "sha512-fB5TBICjHSTGToNTbCCgR8zsngpUkoCM31EMh/M/NEAyNg90i5rUuG0dnNNBML2n0BzM0nBE3sPvo2SEWf6jlA==", - "dev": true - }, - "eslint-plugin-chai-expect": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-chai-expect/-/eslint-plugin-chai-expect-3.0.0.tgz", - "integrity": "sha512-NS0YBcToJl+BRKBSMCwRs/oHJIX67fG5Gvb4tGked+9Wnd1/PzKijd82B2QVKcSSOwRe+pp4RAJ2AULeck4eQw==", - "dev": true, - "requires": {} - }, - "eslint-plugin-chai-expect-keywords": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-chai-expect-keywords/-/eslint-plugin-chai-expect-keywords-2.1.0.tgz", - "integrity": "sha512-3F4QgEGQqAO7DXXltNKyw8JaSIHniUfhJHO75GnOwKlhz6bIKFxyXtySxSZAx6v1/CwCDp7kjYY/YPHJJFsYPA==", - "dev": true - }, - "eslint-plugin-chai-friendly": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.7.2.tgz", - "integrity": "sha512-LOIfGx5sZZ5FwM1shr2GlYAWV9Omdi+1/3byuVagvQNoGUuU0iHhp7AfjA1uR+4dJ4Isfb4+FwBJgQajIw9iAg==", - "dev": true, - "requires": {} - }, - "eslint-plugin-compat": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-4.0.0.tgz", - "integrity": "sha512-lg9CPq0bsGxNXcLZgxqVAYsUUELIKZPRiwnJJQOHH910zCHEiscO00Sp+w9wflKEa/OtVaYfNhI2jOViRPZtjw==", - "dev": true, - "requires": { - "@mdn/browser-compat-data": "^3.3.14", - "ast-metadata-inferer": "^0.7.0", - "browserslist": "^4.16.8", - "caniuse-lite": "^1.0.30001267", - "core-js": "^3.16.2", - "find-up": "^5.0.0", - "lodash.memoize": "4.1.2", - "semver": "7.3.5" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "eslint-plugin-cypress": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.12.1.tgz", - "integrity": "sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA==", - "dev": true, - "requires": { - "globals": "^11.12.0" - } - }, - "eslint-plugin-eslint-comments": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", - "integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "ignore": "^5.0.5" - } - }, - "eslint-plugin-html": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-6.2.0.tgz", - "integrity": "sha512-vi3NW0E8AJombTvt8beMwkL1R/fdRWl4QSNRNMhVQKWm36/X0KF0unGNAY4mqUF06mnwVWZcIcerrCnfn9025g==", - "dev": true, - "requires": { - "htmlparser2": "^7.1.2" - } - }, "eslint-plugin-import": { "version": "2.25.3", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==", "dev": true, + "peer": true, "requires": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", @@ -30694,89 +30115,13 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "peer": true, "requires": { "esutils": "^2.0.2" } } } }, - "eslint-plugin-jsdoc": { - "version": "37.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-37.2.0.tgz", - "integrity": "sha512-ca7s/DD1mMObZQ2Y0n0DO/KnFV+FqCX6ztir8pcSuylg3GGCREIisn36P/0cRySuWW/7Y7MNCuUDqtKdgLPU7Q==", - "dev": true, - "requires": { - "@es-joy/jsdoccomment": "0.13.0", - "comment-parser": "1.3.0", - "debug": "^4.3.3", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "^2.0.0", - "regextras": "^0.8.0", - "semver": "^7.3.5", - "spdx-expression-parse": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "eslint-plugin-markdown": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-2.2.1.tgz", - "integrity": "sha512-FgWp4iyYvTFxPwfbxofTvXxgzPsDuSKHQy2S+a8Ve6savbujey+lgrFFbXQA0HPygISpRYWYBjooPzhYSF81iA==", - "dev": true, - "requires": { - "mdast-util-from-markdown": "^0.8.5" - } - }, - "eslint-plugin-no-unsanitized": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.1.tgz", - "integrity": "sha512-y/lAMWnPPC7RYuUdxlEL/XiCL8FehN9h9s3Kjqbp/Kv0i9NZs+IXSC2kS546Fa4Bumwy31HlVS/OdWX0Kxb5Xg==", - "dev": true, - "requires": {} - }, - "eslint-plugin-no-use-extend-native": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-no-use-extend-native/-/eslint-plugin-no-use-extend-native-0.5.0.tgz", - "integrity": "sha512-dBNjs8hor8rJgeXLH4HTut5eD3RGWf9JUsadIfuL7UosVQ/dnvOKwxEcRrXrFxrMZ8llUVWT+hOimxJABsAUzQ==", - "dev": true, - "requires": { - "is-get-set-prop": "^1.0.0", - "is-js-type": "^2.0.0", - "is-obj-prop": "^1.0.0", - "is-proto-prop": "^2.0.0" - } - }, "eslint-plugin-node": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", @@ -30801,21 +30146,6 @@ "regexpp": "^3.0.0" } }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -30825,17 +30155,78 @@ } }, "eslint-plugin-promise": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz", - "integrity": "sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==", + "version": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz", + "integrity": "sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==", "dev": true, + "peer": true, "requires": {} }, - "eslint-plugin-standard": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.1.0.tgz", - "integrity": "sha512-ZL7+QRixjTR6/528YNGyDotyffm5OQst/sGxKDwGb9Uqs4In5Egi4+jbobhqJoyoCM6/7v/1A5fhQ7ScMtDjaQ==", - "dev": true + "eslint-plugin-react": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.25.3.tgz", + "integrity": "sha512-ZMbFvZ1WAYSZKY662MBVEWR45VaBT6KSJCiupjrNlcdakB90juaZeDCbJq19e73JZQubqFtgETohwgAt8u5P6w==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", + "doctrine": "^2.1.0", + "estraverse": "^5.2.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.4", + "object.fromentries": "^2.0.4", + "object.hasown": "^1.0.0", + "object.values": "^1.1.4", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "string.prototype.matchall": "^4.0.5" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } }, "eslint-visitor-keys": { "version": "1.3.0", @@ -30843,6 +30234,17 @@ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -30866,6 +30268,23 @@ } } }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, "estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", @@ -31593,12 +31012,6 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, - "get-set-props": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-set-props/-/get-set-props-0.1.0.tgz", - "integrity": "sha1-mYR1wXhEVobQsyJG2l3428++jqM=", - "dev": true - }, "get-stdin": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", @@ -32022,26 +31435,6 @@ "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", "dev": true }, - "htmlparser2": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.1.2.tgz", - "integrity": "sha512-d6cqsbJba2nRdg8WW2okyD4ceonFHn9jLFxhwlNcLhQWcFPdxXeJulgOLjLKtAK9T6ahd+GQNZwG9fjmGW7lyg==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.2", - "domutils": "^2.8.0", - "entities": "^3.0.1" - }, - "dependencies": { - "entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true - } - } - }, "http-assert": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz", @@ -32159,9 +31552,9 @@ } }, "i18next": { - "version": "21.6.0", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.0.tgz", - "integrity": "sha512-RjNuACL35wWZgtkyMcjcCmK7R72u3P6jTNbGKzrvHGI9M0iK5Vn1DsBIwOByppaXLIbe0viJ79Nz2h8w1UwPoQ==", + "version": "21.6.4", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.4.tgz", + "integrity": "sha512-pk0Utxtq5g//Q9ONQ0w3+PRSwOFJ7+m4rAekhHHg1Xql0KcUjJU7DzmzweGy6DsrIQ1GM/t57wLeeGuyGKtjTg==", "requires": { "@babel/runtime": "^7.12.0" } @@ -32202,6 +31595,24 @@ "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==", "dev": true }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "import-meta-resolve": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-1.1.1.tgz", @@ -32505,16 +31916,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-get-set-prop": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-get-set-prop/-/is-get-set-prop-1.0.0.tgz", - "integrity": "sha1-JzGHfk14pqae3M5rudaLB3nnYxI=", - "dev": true, - "requires": { - "get-set-props": "^0.1.0", - "lowercase-keys": "^1.0.0" - } - }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -32530,15 +31931,6 @@ "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", "dev": true }, - "is-js-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-js-type/-/is-js-type-2.0.0.tgz", - "integrity": "sha1-c2FwBtZZtOtHKbunR9KHgt8PfiI=", - "dev": true, - "requires": { - "js-types": "^1.0.0" - } - }, "is-lambda": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", @@ -32583,16 +31975,6 @@ "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", "dev": true }, - "is-obj-prop": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-obj-prop/-/is-obj-prop-1.0.0.tgz", - "integrity": "sha1-s03nnEULjXxzqyzfZ9yHWtuF+A4=", - "dev": true, - "requires": { - "lowercase-keys": "^1.0.0", - "obj-props": "^1.0.0" - } - }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -32626,16 +32008,6 @@ "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", "dev": true }, - "is-proto-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-proto-prop/-/is-proto-prop-2.0.0.tgz", - "integrity": "sha512-jl3NbQ/fGLv5Jhan4uX+Ge9ohnemqyblWVVCpAvtTQzNFvV2xhJq+esnkIbYQ9F1nITXoLfDDQLp7LBw/zzncg==", - "dev": true, - "requires": { - "lowercase-keys": "^1.0.0", - "proto-props": "^2.0.0" - } - }, "is-reference": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", @@ -33003,12 +32375,6 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, - "js-types": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/js-types/-/js-types-1.0.0.tgz", - "integrity": "sha1-0kLmSU7Vcq08koCfyL7X92h8vwM=", - "dev": true - }, "js-yaml": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", @@ -33073,21 +32439,9 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true } } }, - "jsdoc-type-pratt-parser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-2.0.0.tgz", - "integrity": "sha512-sUuj2j48wxrEpbFjDp1sAesAxPiLT+z0SWVmMafyIINs6Lj5gIPKh3VrkBZu4E/Dv+wHpOot0m6H8zlHQjwqeQ==", - "dev": true - }, "jsdom": { "version": "16.4.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", @@ -33215,9 +32569,9 @@ } }, "jspdf": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.4.0.tgz", - "integrity": "sha512-nsZ92YfbNG/EimR1yqmOkxf2D4iJRypBsw7pvP1aPiIEnoGITaLl6XDR/GYA36/R29vMZSBedpEhBCzutSGytA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.0.tgz", + "integrity": "sha512-XT0E2m8A9P1xl7ItA2OUbmhokzbDQEyZEdWQZD2olADiTiBEZGDRiK1J1zWxBRUG2KezQJOZq//GYZTkvEZuJg==", "requires": { "@babel/runtime": "^7.14.0", "atob": "^2.1.2", @@ -33241,6 +32595,16 @@ "verror": "1.10.0" } }, + "jsx-ast-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", + "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "object.assign": "^4.1.2" + } + }, "keygrip": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", @@ -33627,12 +32991,6 @@ "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", "dev": true }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, "lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -33782,12 +33140,6 @@ "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", "dev": true }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -35380,13 +34732,6 @@ "randombytes": "^2.1.0" } }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "peer": true - }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -36042,12 +35387,6 @@ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, - "obj-props": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/obj-props/-/obj-props-1.3.0.tgz", - "integrity": "sha512-k2Xkjx5wn6eC3537SWAXHzB6lkI81kS+icMKMkh4nG3w7shWG6MaWOBrNvhWVOszrtL5uxdfymQQfPUxwY+2eg==", - "dev": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -36161,6 +35500,38 @@ "object-keys": "^1.1.1" } }, + "object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -36771,6 +36142,43 @@ "pngjs": "^3.0.0" } }, + "pkg-conf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", + "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "load-json-file": "^5.2.0" + }, + "dependencies": { + "load-json-file": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, "pkg-dir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", @@ -36780,6 +36188,60 @@ "find-up": "^3.0.0" } }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + } + } + }, "pngjs": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", @@ -36884,11 +36346,16 @@ "retry": "^0.12.0" } }, - "proto-props": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/proto-props/-/proto-props-2.0.0.tgz", - "integrity": "sha512-2yma2tog9VaRZY2mn3Wq51uiSW4NcPYT1cQdBagwyrznrilKSZwIZ0UG3ZPL/mx+axEns0hE35T5ufOYZXEnBQ==", - "dev": true + "prop-types": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.0.tgz", + "integrity": "sha512-fDGekdaHh65eI3lMi5OnErU6a8Ighg2KjcjQxO7m8VHyWjcPyj5kiOgV1LQDOOOgVy3+5FgjXvdSSX7B8/5/4g==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } }, "proxy-from-env": { "version": "1.0.0", @@ -37018,6 +36485,12 @@ "safe-buffer": "^5.1.0" } }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, "read-only-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", @@ -37065,6 +36538,61 @@ } } }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + } + } + }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -37197,6 +36725,22 @@ } } }, + "regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, "regexpu-core": { "version": "4.8.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", @@ -37211,12 +36755,6 @@ "unicode-match-property-value-ecmascript": "^2.0.0" } }, - "regextras": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.8.0.tgz", - "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==", - "dev": true - }, "regjsgen": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", @@ -37961,9 +37499,9 @@ } }, "rollup": { - "version": "2.61.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.61.0.tgz", - "integrity": "sha512-teQ+T1mUYbyvGyUavCodiyA9hD4DxwYZJwr/qehZGhs1Z49vsmzelMVYMxGU4ZhGRKxYPupHuz5yzm/wj7VpWA==", + "version": "2.62.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.62.0.tgz", + "integrity": "sha512-cJEQq2gwB0GWMD3rYImefQTSjrPYaC6s4J9pYqnstVLJ1CHa/aZNVkD4Epuvg4iLeMA4KRiq7UM7awKK6j7jcw==", "requires": { "fsevents": "~2.3.2" }, @@ -39042,6 +38580,126 @@ "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz", "integrity": "sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==" }, + "standard": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/standard/-/standard-16.0.4.tgz", + "integrity": "sha512-2AGI874RNClW4xUdM+bg1LRXVlYLzTNEkHmTG5mhyn45OhbgwA+6znowkOGYy+WMb5HRyELvtNy39kcdMQMcYQ==", + "dev": true, + "requires": { + "eslint": "~7.18.0", + "eslint-config-standard": "16.0.3", + "eslint-config-standard-jsx": "10.0.0", + "eslint-plugin-import": "~2.24.2", + "eslint-plugin-node": "~11.1.0", + "eslint-plugin-promise": "~5.1.0", + "eslint-plugin-react": "~7.25.1", + "standard-engine": "^14.0.1" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "eslint-plugin-import": { + "version": "2.24.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz", + "integrity": "sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.6.2", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.6.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.4", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + } + }, + "eslint-plugin-promise": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.1.tgz", + "integrity": "sha512-XgdcdyNzHfmlQyweOPTxmc7pIsS6dE4MvwhXWMQ2Dxs1XAL2GJDilUsjWen6TWik0aSI+zD/PqocZBblcm9rdA==", + "dev": true, + "requires": {} + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + } + } + }, + "standard-engine": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-14.0.1.tgz", + "integrity": "sha512-7FEzDwmHDOGva7r9ifOzD3BGdTbA7ujJ50afLVdW/tK14zQEptJjbFuUfn50irqdHDcTbNh0DTIoMPynMCXb0Q==", + "dev": true, + "requires": { + "get-stdin": "^8.0.0", + "minimist": "^1.2.5", + "pkg-conf": "^3.1.0", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true + } + } + }, "start-server-and-test": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.14.0.tgz", @@ -39261,14 +38919,30 @@ } }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.matchall": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", + "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" } }, "string.prototype.padend": { @@ -39302,12 +38976,12 @@ } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, "strip-bom": { @@ -39337,6 +39011,12 @@ "min-indent": "^1.0.1" } }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "strtok3": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.1.3.tgz", @@ -39402,23 +39082,22 @@ } }, "table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.5.tgz", + "integrity": "sha512-LFNeryOqiQHqCVKzhkymKwt6ozeRhlm8IL1mE8rNUurkir4heF6PzMyRgaTa4tlyPTGGgXuvVOF/OLWiH09Lqw==", "dev": true, "requires": { "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "dependencies": { "ajv": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz", - "integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==", + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz", + "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -40006,12 +39685,6 @@ "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", "dev": true }, - "ua-parser-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", - "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==", - "dev": true - }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -41341,6 +41014,12 @@ "dev": true, "requires": {} }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, "xhr": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz", diff --git a/package.json b/package.json index 5b509905..41ae2b9d 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "node": ">=10" }, "scripts": { - "lint": "eslint --ext js,html,md .", + "lint": "standard .", "test": "run-s cypress:instrument cypress:test", "build": "rollup -c", "build:watch": "rollup -c --watch", @@ -67,62 +67,55 @@ "not IE 11", "not OperaMini all" ], + "standard": { + "ignore": [ + "archive/" + ], + "globals": [ + "cy", + "assert" + ], + "env": [ + "mocha", + "browser" + ] + }, "dependencies": { "@babel/polyfill": "7.12.1", "browser-fs-access": "0.23.0", "canvg": "3.0.9", - "core-js": "3.19.3", + "core-js": "3.20.1", "elix": "15.0.1", "html2canvas": "1.3.3", - "i18next": "21.6.0", - "jspdf": "2.4.0", + "i18next": "21.6.4", + "jspdf": "2.5.0", "pathseg": "1.2.1", "regenerator-runtime": "0.13.9", "rollup-plugin-polyfill-node": "0.8.0", "svg2pdf.js": "2.2.0" }, "devDependencies": { - "@babel/core": "7.16.0", - "@babel/preset-env": "7.16.4", - "@babel/register": "7.16.0", - "@babel/runtime-corejs3": "7.16.3", + "@babel/core": "7.16.5", + "@babel/preset-env": "7.16.5", + "@babel/register": "7.16.5", + "@babel/runtime-corejs3": "7.16.5", "@cypress/code-coverage": "3.9.12", "@cypress/fiddle": "1.19.3", - "@fintechstudios/eslint-plugin-chai-as-promised": "3.1.0", "@rollup/plugin-babel": "5.3.0", "@rollup/plugin-commonjs": "^18", "@rollup/plugin-dynamic-import-vars": "1.4.1", - "@rollup/plugin-node-resolve": "13.0.6", + "@rollup/plugin-node-resolve": "13.1.1", "@rollup/plugin-replace": "3.0.0", "@rollup/plugin-url": "6.1.0", "@web/dev-server": "0.1.28", - "@web/dev-server-esbuild": "^0.2.16", "@web/dev-server-rollup": "0.3.13", "babel-plugin-transform-object-rest-spread": "7.0.0-beta.3", "copyfiles": "2.4.1", - "core-js-bundle": "3.19.3", + "core-js-bundle": "3.20.1", "cp-cli": "2.0.0", - "cypress": "9.1.1", + "cypress": "9.2.0", "cypress-multi-reporters": "1.5.0", "cypress-plugin-snapshots": "1.4.4", - "eslint": "^7", - "eslint-config-standard": "16.0.3", - "eslint-plugin-array-func": "3.1.7", - "eslint-plugin-chai-expect": "3.0.0", - "eslint-plugin-chai-expect-keywords": "2.1.0", - "eslint-plugin-chai-friendly": "0.7.2", - "eslint-plugin-compat": "4.0.0", - "eslint-plugin-cypress": "2.12.1", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-html": "6.2.0", - "eslint-plugin-import": "2.25.3", - "eslint-plugin-jsdoc": "37.2.0", - "eslint-plugin-markdown": "2.2.1", - "eslint-plugin-no-unsanitized": "4.0.1", - "eslint-plugin-no-use-extend-native": "0.5.0", - "eslint-plugin-node": "11.1.0", - "eslint-plugin-promise": "5.2.0", - "eslint-plugin-standard": "4.1.0", "jamilih": "0.54.0", "jsdoc": "3.6.7", "node-static": "0.7.11", @@ -135,7 +128,7 @@ "remark-cli": "10.0.1", "remark-lint-ordered-list-marker-value": "3.1.1", "rimraf": "3.0.2", - "rollup": "2.61.0", + "rollup": "2.62.0", "rollup-plugin-copy": "3.4.0", "rollup-plugin-filesize": "9.1.1", "rollup-plugin-html": "^0.2.1", @@ -143,6 +136,7 @@ "rollup-plugin-progress": "1.1.2", "rollup-plugin-re": "1.0.7", "rollup-plugin-terser": "7.0.2", + "standard": "16.0.4", "start-server-and-test": "1.14.0" } } diff --git a/rollup.config.js b/rollup.config.js index 6a678ad9..7f88dbfc 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -3,42 +3,42 @@ // This rollup script is run by the command: // 'npm run build' -import path from 'path'; -import { lstatSync, readdirSync } from 'fs'; -import rimraf from 'rimraf'; -import babel from '@rollup/plugin-babel'; -import copy from 'rollup-plugin-copy'; -import { nodeResolve } from '@rollup/plugin-node-resolve'; -import commonjs from '@rollup/plugin-commonjs'; -import nodePolyfills from 'rollup-plugin-node-polyfills'; -import url from '@rollup/plugin-url'; // for XML/SVG files +import path from 'path' +import { lstatSync, readdirSync } from 'fs' +import rimraf from 'rimraf' +import babel from '@rollup/plugin-babel' +import copy from 'rollup-plugin-copy' +import { nodeResolve } from '@rollup/plugin-node-resolve' +import commonjs from '@rollup/plugin-commonjs' +import nodePolyfills from 'rollup-plugin-node-polyfills' +import url from '@rollup/plugin-url' // for XML/SVG files // eslint-disable-next-line node/no-extraneous-import -import html from 'rollup-plugin-html'; +import html from 'rollup-plugin-html' -import dynamicImportVars from '@rollup/plugin-dynamic-import-vars'; -import { terser } from 'rollup-plugin-terser'; +import dynamicImportVars from '@rollup/plugin-dynamic-import-vars' +import { terser } from 'rollup-plugin-terser' // import progress from 'rollup-plugin-progress'; -import filesize from 'rollup-plugin-filesize'; +import filesize from 'rollup-plugin-filesize' // utility function const getDirectories = (source) => { const isDirectory = (dir) => { - return lstatSync(dir).isDirectory(); - }; - return readdirSync(source).map((name) => path.join(source, name)).filter((i) => isDirectory(i)); -}; + return lstatSync(dir).isDirectory() + } + return readdirSync(source).map((name) => path.join(source, name)).filter((i) => isDirectory(i)) +} // capture the list of files to build for extensions and ext-locales -const extensionDirs = getDirectories('src/editor/extensions'); +const extensionDirs = getDirectories('src/editor/extensions') -const dest = [ 'dist/editor' ]; +const dest = ['dist/editor'] // remove existing distribution -rimraf('./dist', () => console.info('recreating dist')); +rimraf('./dist', () => console.info('recreating dist')) // config for svgedit core module -const config = [ { - input: [ 'src/editor/Editor.js' ], +const config = [{ + input: ['src/editor/Editor.js'], output: [ { format: 'es', @@ -80,8 +80,8 @@ const config = [ { dest: 'dist/editor', rename: 'iife-index.html', transform: (contents) => { - const replace1 = contents.toString().replace("import Editor from './Editor.js'", "/* import Editor from './xdomain-Editor.js' */"); - return replace1.replace(' \ No newline at end of file diff --git a/src/editor/locale.js b/src/editor/locale.js index 1593357e..33fa9cd2 100644 --- a/src/editor/locale.js +++ b/src/editor/locale.js @@ -8,7 +8,7 @@ * */ -import i18next from 'i18next'; +import i18next from 'i18next' /** * Used, for example, in the ImageLibs extension, to present libraries @@ -25,7 +25,7 @@ import i18next from 'i18next'; * @typedef {PlainObject} module:locale.LocaleSelectorValue */ -let langParam; +let langParam /** * The "data" property is generally set to an an array of objects with @@ -61,19 +61,18 @@ let langParam; export const putLocale = async function (givenParam, goodLangs) { if (givenParam) { - langParam = givenParam; + langParam = givenParam } else if (navigator.userLanguage) { // Explorer - langParam = navigator.userLanguage; + langParam = navigator.userLanguage } else if (navigator.language) { // FF, Opera, ... - langParam = navigator.language; + langParam = navigator.language } // Set to English if language is not in list of good langs if (!goodLangs.includes(langParam) && langParam !== 'test') { - langParam = 'en'; + langParam = 'en' } - // eslint-disable-next-line no-unsanitized/method - const module = await import(`./locale/lang.${encodeURIComponent(langParam)}.js`); + const module = await import(`./locale/lang.${encodeURIComponent(langParam)}.js`) i18next.init({ lng: langParam, debug: false, @@ -82,10 +81,10 @@ export const putLocale = async function (givenParam, goodLangs) { translation: module.default } } - }); - return { langParam, i18next }; -}; + }) + return { langParam, i18next } +} export const t = function (key) { - return i18next.t(key); -}; \ No newline at end of file + return i18next.t(key) +} diff --git a/src/editor/locale/lang.af.js b/src/editor/locale/lang.af.js index d1ab9360..87b5bec0 100644 --- a/src/editor/locale/lang.af.js +++ b/src/editor/locale/lang.af.js @@ -203,7 +203,7 @@ export default { snapping_onoff: 'Snapping on/off', snapping_stepsize: 'Snapping Step-Size:', grid_color: 'Grid color', - done: "Done", + done: 'Done', change_xxx_color: 'Change xxx color', pick_paint_opavity: 'Pick a {{newValue}} Paint and Opacity', open_color_picker: 'Click To Open Color Picker', @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.ar.js b/src/editor/locale/lang.ar.js index 1724566a..87b02377 100644 --- a/src/editor/locale/lang.ar.js +++ b/src/editor/locale/lang.ar.js @@ -203,7 +203,7 @@ export default { snapping_onoff: 'Snapping on/off', snapping_stepsize: 'Snapping Step-Size:', grid_color: 'Grid color', - done: "Done", + done: 'Done', change_xxx_color: 'Change xxx color', pick_paint_opavity: 'Pick a {{newValue}} Paint and Opacity', open_color_picker: 'Click To Open Color Picker', @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.az.js b/src/editor/locale/lang.az.js index 28ea29da..3bb7d8e3 100644 --- a/src/editor/locale/lang.az.js +++ b/src/editor/locale/lang.az.js @@ -203,7 +203,7 @@ export default { snapping_onoff: 'Snapping on/off', snapping_stepsize: 'Snapping Step-Size:', grid_color: 'Grid color', - done: "Done", + done: 'Done', change_xxx_color: 'Change xxx color', pick_paint_opavity: 'Pick a {{newValue}} Paint and Opacity', open_color_picker: 'Click To Open Color Picker', @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.be.js b/src/editor/locale/lang.be.js index 95b83323..bc0be1e7 100644 --- a/src/editor/locale/lang.be.js +++ b/src/editor/locale/lang.be.js @@ -203,7 +203,7 @@ export default { snapping_onoff: 'Snapping on/off', snapping_stepsize: 'Snapping Step-Size:', grid_color: 'Grid color', - done: "Done", + done: 'Done', change_xxx_color: 'Change xxx color', pick_paint_opavity: 'Pick a {{newValue}} Paint and Opacity', open_color_picker: 'Click To Open Color Picker', @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.bg.js b/src/editor/locale/lang.bg.js index 67fbe243..c4a34d31 100644 --- a/src/editor/locale/lang.bg.js +++ b/src/editor/locale/lang.bg.js @@ -203,7 +203,7 @@ export default { snapping_onoff: 'Snapping on/off', snapping_stepsize: 'Snapping Step-Size:', grid_color: 'Grid color', - done: "Done", + done: 'Done', change_xxx_color: 'Change xxx color', pick_paint_opavity: 'Pick a {{newValue}} Paint and Opacity', open_color_picker: 'Click To Open Color Picker', @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.ca.js b/src/editor/locale/lang.ca.js index aeba9ad8..d1d5fe19 100644 --- a/src/editor/locale/lang.ca.js +++ b/src/editor/locale/lang.ca.js @@ -206,7 +206,7 @@ export default { snapping_onoff: 'Snapping on/off', snapping_stepsize: 'Snapping Step-Size:', grid_color: 'Grid color', - done: "Done", + done: 'Done', change_xxx_color: 'Change xxx color', pick_paint_opavity: 'Pick a {{newValue}} Paint and Opacity', open_color_picker: 'Click To Open Color Picker', @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.cs.js b/src/editor/locale/lang.cs.js index dfca60d7..efbf18d7 100644 --- a/src/editor/locale/lang.cs.js +++ b/src/editor/locale/lang.cs.js @@ -206,7 +206,7 @@ export default { snapping_onoff: 'Snapping on/off', snapping_stepsize: 'Snapping Step-Size:', grid_color: 'Grid color', - done: "Done", + done: 'Done', change_xxx_color: 'Change xxx color', pick_paint_opavity: 'Pick a {{newValue}} Paint and Opacity', open_color_picker: 'Click To Open Color Picker', @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.cy.js b/src/editor/locale/lang.cy.js index a6e1c451..447df759 100644 --- a/src/editor/locale/lang.cy.js +++ b/src/editor/locale/lang.cy.js @@ -206,7 +206,7 @@ export default { snapping_onoff: 'Snapping on/off', snapping_stepsize: 'Snapping Step-Size:', grid_color: 'Grid color', - done: "Done", + done: 'Done', change_xxx_color: 'Change xxx color', pick_paint_opavity: 'Pick a {{newValue}} Paint and Opacity', open_color_picker: 'Click To Open Color Picker', @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.da.js b/src/editor/locale/lang.da.js index 85ce8179..767cd33e 100644 --- a/src/editor/locale/lang.da.js +++ b/src/editor/locale/lang.da.js @@ -205,7 +205,7 @@ export default { snapping_onoff: 'Snapping on/off', snapping_stepsize: 'Snapping Step-Size:', grid_color: 'Grid color', - done: "Done", + done: 'Done', change_xxx_color: 'Change xxx color', pick_paint_opavity: 'Pick a {{newValue}} Paint and Opacity', open_color_picker: 'Click To Open Color Picker', @@ -290,4 +290,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.de.js b/src/editor/locale/lang.de.js index 1416e352..bd86bcbc 100644 --- a/src/editor/locale/lang.de.js +++ b/src/editor/locale/lang.de.js @@ -206,7 +206,7 @@ export default { snapping_onoff: 'Einrasten an/aus', snapping_stepsize: 'Einrastabstand:', grid_color: 'Gitterfarbe', - done: "Done", + done: 'Done', change_xxx_color: 'Change xxx color', pick_paint_opavity: 'Pick a {{newValue}} Paint and Opacity', open_color_picker: 'Click To Open Color Picker', @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.el.js b/src/editor/locale/lang.el.js index 088f7b0c..d3bd1078 100644 --- a/src/editor/locale/lang.el.js +++ b/src/editor/locale/lang.el.js @@ -206,7 +206,7 @@ export default { snapping_onoff: 'Snapping on/off', snapping_stepsize: 'Snapping Step-Size:', grid_color: 'Grid color', - done: "Done", + done: 'Done', change_xxx_color: 'Change xxx color', pick_paint_opavity: 'Pick a {{newValue}} Paint and Opacity', open_color_picker: 'Click To Open Color Picker', @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.en.js b/src/editor/locale/lang.en.js index 5751d9d0..688cceaa 100644 --- a/src/editor/locale/lang.en.js +++ b/src/editor/locale/lang.en.js @@ -305,4 +305,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.es.js b/src/editor/locale/lang.es.js index 8f3acc84..0de1cf7b 100644 --- a/src/editor/locale/lang.es.js +++ b/src/editor/locale/lang.es.js @@ -206,7 +206,7 @@ export default { snapping_onoff: 'Snapping on/off', snapping_stepsize: 'Snapping Step-Size:', grid_color: 'Grid color', - done: "Done", + done: 'Done', change_xxx_color: 'Change xxx color', pick_paint_opavity: 'Pick a {{newValue}} Paint and Opacity', open_color_picker: 'Click To Open Color Picker', @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.et.js b/src/editor/locale/lang.et.js index 8a08b26a..c03f754a 100644 --- a/src/editor/locale/lang.et.js +++ b/src/editor/locale/lang.et.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.fa.js b/src/editor/locale/lang.fa.js index 2e0431a8..2eb539ee 100644 --- a/src/editor/locale/lang.fa.js +++ b/src/editor/locale/lang.fa.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.fi.js b/src/editor/locale/lang.fi.js index c1558af2..6e24556f 100644 --- a/src/editor/locale/lang.fi.js +++ b/src/editor/locale/lang.fi.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.fr.js b/src/editor/locale/lang.fr.js index e8f85fb5..1e5bf3ae 100644 --- a/src/editor/locale/lang.fr.js +++ b/src/editor/locale/lang.fr.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.fy.js b/src/editor/locale/lang.fy.js index 14a86e70..6987168f 100644 --- a/src/editor/locale/lang.fy.js +++ b/src/editor/locale/lang.fy.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.ga.js b/src/editor/locale/lang.ga.js index 92bb6a76..563383f5 100644 --- a/src/editor/locale/lang.ga.js +++ b/src/editor/locale/lang.ga.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.gl.js b/src/editor/locale/lang.gl.js index be13584a..737df7ec 100644 --- a/src/editor/locale/lang.gl.js +++ b/src/editor/locale/lang.gl.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.he.js b/src/editor/locale/lang.he.js index fe7868df..b2636ebf 100755 --- a/src/editor/locale/lang.he.js +++ b/src/editor/locale/lang.he.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.hi.js b/src/editor/locale/lang.hi.js index 74df0892..33aa8040 100644 --- a/src/editor/locale/lang.hi.js +++ b/src/editor/locale/lang.hi.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.hr.js b/src/editor/locale/lang.hr.js index ff8f322b..98910eda 100644 --- a/src/editor/locale/lang.hr.js +++ b/src/editor/locale/lang.hr.js @@ -290,4 +290,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.hu.js b/src/editor/locale/lang.hu.js index 89bc9e69..9b55ebae 100644 --- a/src/editor/locale/lang.hu.js +++ b/src/editor/locale/lang.hu.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.hy.js b/src/editor/locale/lang.hy.js index 1e164027..04feadc4 100644 --- a/src/editor/locale/lang.hy.js +++ b/src/editor/locale/lang.hy.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.id.js b/src/editor/locale/lang.id.js index 3b8bf7b2..f41de36c 100644 --- a/src/editor/locale/lang.id.js +++ b/src/editor/locale/lang.id.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.is.js b/src/editor/locale/lang.is.js index b99e17a3..3bddc05d 100644 --- a/src/editor/locale/lang.is.js +++ b/src/editor/locale/lang.is.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.it.js b/src/editor/locale/lang.it.js index 0438fe4a..c20b3afb 100644 --- a/src/editor/locale/lang.it.js +++ b/src/editor/locale/lang.it.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.ja.js b/src/editor/locale/lang.ja.js index b911c792..e402f66c 100644 --- a/src/editor/locale/lang.ja.js +++ b/src/editor/locale/lang.ja.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.ko.js b/src/editor/locale/lang.ko.js index 3e2db20d..6aabdaa8 100644 --- a/src/editor/locale/lang.ko.js +++ b/src/editor/locale/lang.ko.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.lt.js b/src/editor/locale/lang.lt.js index d8c75284..22fa0937 100644 --- a/src/editor/locale/lang.lt.js +++ b/src/editor/locale/lang.lt.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.lv.js b/src/editor/locale/lang.lv.js index 4277e085..e3aea3a5 100644 --- a/src/editor/locale/lang.lv.js +++ b/src/editor/locale/lang.lv.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.mk.js b/src/editor/locale/lang.mk.js index 65295d8b..fab7935e 100644 --- a/src/editor/locale/lang.mk.js +++ b/src/editor/locale/lang.mk.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.ms.js b/src/editor/locale/lang.ms.js index 567ab3b5..85de8294 100644 --- a/src/editor/locale/lang.ms.js +++ b/src/editor/locale/lang.ms.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.mt.js b/src/editor/locale/lang.mt.js index 62d43382..fffa4223 100644 --- a/src/editor/locale/lang.mt.js +++ b/src/editor/locale/lang.mt.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.nl.js b/src/editor/locale/lang.nl.js index 9ed39cf2..005de475 100644 --- a/src/editor/locale/lang.nl.js +++ b/src/editor/locale/lang.nl.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.no.js b/src/editor/locale/lang.no.js index 1ea5b67c..a17e787b 100644 --- a/src/editor/locale/lang.no.js +++ b/src/editor/locale/lang.no.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.pl.js b/src/editor/locale/lang.pl.js index a22a66e3..68fc49e0 100644 --- a/src/editor/locale/lang.pl.js +++ b/src/editor/locale/lang.pl.js @@ -292,4 +292,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.pt-BR.js b/src/editor/locale/lang.pt-BR.js index fee83565..d12fcee2 100644 --- a/src/editor/locale/lang.pt-BR.js +++ b/src/editor/locale/lang.pt-BR.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.pt-PT.js b/src/editor/locale/lang.pt-PT.js index 5478ec72..7ad581af 100644 --- a/src/editor/locale/lang.pt-PT.js +++ b/src/editor/locale/lang.pt-PT.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.ro.js b/src/editor/locale/lang.ro.js index a363ade6..d31be102 100644 --- a/src/editor/locale/lang.ro.js +++ b/src/editor/locale/lang.ro.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.ru.js b/src/editor/locale/lang.ru.js index ec2cc426..186855c3 100644 --- a/src/editor/locale/lang.ru.js +++ b/src/editor/locale/lang.ru.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.sk.js b/src/editor/locale/lang.sk.js index 14cc9518..9a1c09b7 100644 --- a/src/editor/locale/lang.sk.js +++ b/src/editor/locale/lang.sk.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.sl.js b/src/editor/locale/lang.sl.js index d25601b9..538e0bbb 100644 --- a/src/editor/locale/lang.sl.js +++ b/src/editor/locale/lang.sl.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.sq.js b/src/editor/locale/lang.sq.js index 3d49c291..2c248d41 100644 --- a/src/editor/locale/lang.sq.js +++ b/src/editor/locale/lang.sq.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.sr.js b/src/editor/locale/lang.sr.js index 2ee33d3f..8ef5443d 100644 --- a/src/editor/locale/lang.sr.js +++ b/src/editor/locale/lang.sr.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.sv.js b/src/editor/locale/lang.sv.js index aa6b6b05..6d8ebc67 100644 --- a/src/editor/locale/lang.sv.js +++ b/src/editor/locale/lang.sv.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.sw.js b/src/editor/locale/lang.sw.js index 2656d056..43cddb3c 100644 --- a/src/editor/locale/lang.sw.js +++ b/src/editor/locale/lang.sw.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.test.js b/src/editor/locale/lang.test.js index a241175f..e090dc94 100644 --- a/src/editor/locale/lang.test.js +++ b/src/editor/locale/lang.test.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.th.js b/src/editor/locale/lang.th.js index 0fc85a43..ce3adcb5 100644 --- a/src/editor/locale/lang.th.js +++ b/src/editor/locale/lang.th.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.tl.js b/src/editor/locale/lang.tl.js index 93f14f30..ad9756ad 100644 --- a/src/editor/locale/lang.tl.js +++ b/src/editor/locale/lang.tl.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.tr.js b/src/editor/locale/lang.tr.js index a86e519e..18386b7c 100644 --- a/src/editor/locale/lang.tr.js +++ b/src/editor/locale/lang.tr.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.uk.js b/src/editor/locale/lang.uk.js index ba9eca29..b1982e22 100644 --- a/src/editor/locale/lang.uk.js +++ b/src/editor/locale/lang.uk.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.vi.js b/src/editor/locale/lang.vi.js index 0c373791..373a44e3 100644 --- a/src/editor/locale/lang.vi.js +++ b/src/editor/locale/lang.vi.js @@ -288,4 +288,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.yi.js b/src/editor/locale/lang.yi.js index cf719938..439f6ead 100644 --- a/src/editor/locale/lang.yi.js +++ b/src/editor/locale/lang.yi.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.zh-CN.js b/src/editor/locale/lang.zh-CN.js index 033a71e7..b8983f5b 100644 --- a/src/editor/locale/lang.zh-CN.js +++ b/src/editor/locale/lang.zh-CN.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.zh-HK.js b/src/editor/locale/lang.zh-HK.js index c9de1bcb..c0d50070 100644 --- a/src/editor/locale/lang.zh-HK.js +++ b/src/editor/locale/lang.zh-HK.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/locale/lang.zh-TW.js b/src/editor/locale/lang.zh-TW.js index 6fc66f84..4df994be 100644 --- a/src/editor/locale/lang.zh-TW.js +++ b/src/editor/locale/lang.zh-TW.js @@ -291,4 +291,4 @@ export default { editorPreferencesMsg: 'By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.', source_dialog_note: 'Copy the contents of this box into a text editor, then save the file with a .svg extension.' } -}; +} diff --git a/src/editor/panels/BottomPanel.js b/src/editor/panels/BottomPanel.js index a9aa4bfe..e9bf5886 100644 --- a/src/editor/panels/BottomPanel.js +++ b/src/editor/panels/BottomPanel.js @@ -1,8 +1,8 @@ -import SvgCanvas from '../../svgcanvas/svgcanvas.js'; -import { jGraduate } from '../components/jgraduate/jQuery.jGraduate.js'; -import BottomPanelHtml from './BottomPanel.html'; +import SvgCanvas from '../../svgcanvas/svgcanvas.js' +import { jGraduate } from '../components/jgraduate/jQuery.jGraduate.js' +import BottomPanelHtml from './BottomPanel.html' -const { $id } = SvgCanvas; +const { $id } = SvgCanvas /* * register actions for left panel @@ -15,99 +15,104 @@ class BottomPanel { * @param {PlainObject} editor svgedit handler */ constructor (editor) { - this.editor = editor; + this.editor = editor } + /** * @type {module} */ get selectedElement () { - return this.editor.selectedElement; + return this.editor.selectedElement } + /** * @type {module} */ get multiselected () { - return this.editor.multiselected; + return this.editor.multiselected } + /** * @type {module} */ changeStrokeWidth (e) { - let val = e.target.value; - if (val === 0 && this.editor.selectedElement && [ 'line', 'polyline' ].includes(this.editor.selectedElement.nodeName)) { - val = 1; + let val = e.target.value + if (val === 0 && this.editor.selectedElement && ['line', 'polyline'].includes(this.editor.selectedElement.nodeName)) { + val = 1 } - this.editor.svgCanvas.setStrokeWidth(val); + this.editor.svgCanvas.setStrokeWidth(val) } + /** * @type {module} */ changeZoom (value) { switch (value) { - case 'canvas': - case 'selection': - case 'layer': - case 'content': - this.editor.zoomChanged(window, value); - break; - default: - { - const zoomlevel = Number(value) / 100; - if (zoomlevel < 0.001) { - value = 0.1; - return; + case 'canvas': + case 'selection': + case 'layer': + case 'content': + this.editor.zoomChanged(window, value) + break + default: + { + const zoomlevel = Number(value) / 100 + if (zoomlevel < 0.001) { + value = 0.1 + return + } + const zoom = this.editor.svgCanvas.getZoom() + const { workarea } = this.editor + this.editor.zoomChanged(window, { + width: 0, + height: 0, + // center pt of scroll position + x: (workarea.scrollLeft + parseFloat(getComputedStyle(workarea, null).width.replace('px', '')) / 2) / zoom, + y: (workarea.scrollTop + parseFloat(getComputedStyle(workarea, null).height.replace('px', '')) / 2) / zoom, + zoom: zoomlevel + }, true) } - const zoom = this.editor.svgCanvas.getZoom(); - const { workarea } = this.editor; - this.editor.zoomChanged(window, { - width: 0, - height: 0, - // center pt of scroll position - x: (workarea.scrollLeft + parseFloat(getComputedStyle(workarea, null).width.replace("px", "")) / 2) / zoom, - y: (workarea.scrollTop + parseFloat(getComputedStyle(workarea, null).height.replace("px", "")) / 2) / zoom, - zoom: zoomlevel - }, true); - } } } + /** * @fires module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate * @returns {void} */ updateToolButtonState () { - const bNoFill = (this.editor.svgCanvas.getColor('fill') === 'none'); - const bNoStroke = (this.editor.svgCanvas.getColor('stroke') === 'none'); - const buttonsNeedingStroke = [ 'tool_fhpath', 'tool_line' ]; + const bNoFill = (this.editor.svgCanvas.getColor('fill') === 'none') + const bNoStroke = (this.editor.svgCanvas.getColor('stroke') === 'none') + const buttonsNeedingStroke = ['tool_fhpath', 'tool_line'] const buttonsNeedingFillAndStroke = [ 'tools_rect', 'tools_ellipse', 'tool_text', 'tool_path' - ]; + ] if (bNoStroke) { buttonsNeedingStroke.forEach((btn) => { // if btn is pressed, change to select button if ($id(btn).pressed) { - this.editor.leftPanel.clickSelect(); + this.editor.leftPanel.clickSelect() } - $id(btn).disabled = true; - }); + $id(btn).disabled = true + }) } else { buttonsNeedingStroke.forEach((btn) => { - $id(btn).disabled = false; - }); + $id(btn).disabled = false + }) } if (bNoStroke && bNoFill) { buttonsNeedingFillAndStroke.forEach((btn) => { // if btn is pressed, change to select button if ($id(btn).pressed) { - this.editor.leftPanel.clickSelect(); + this.editor.leftPanel.clickSelect() } - $id(btn).disabled = true; - }); + $id(btn).disabled = true + }) } else { buttonsNeedingFillAndStroke.forEach((btn) => { - $id(btn).disabled = false; - }); + $id(btn).disabled = false + }) } this.editor.svgCanvas.runExtensions( 'toolButtonStateUpdate', @@ -115,83 +120,88 @@ class BottomPanel { nofill: bNoFill, nostroke: bNoStroke } - ); + ) } + /** * @type {module} */ handleColorPicker (type, evt) { - const { paint } = evt.detail; - this.editor.svgCanvas.setPaint(type, paint); - this.updateToolButtonState(); + const { paint } = evt.detail + this.editor.svgCanvas.setPaint(type, paint) + this.updateToolButtonState() } + /** * @type {module} */ handleStrokeAttr (type, evt) { - this.editor.svgCanvas.setStrokeAttr(type, evt.detail.value); + this.editor.svgCanvas.setStrokeAttr(type, evt.detail.value) } + /** * @type {module} */ handleOpacity (evt) { - const val = Number.parseInt(evt.currentTarget.value.split('%')[0]); - this.editor.svgCanvas.setOpacity(val / 100); + const val = Number.parseInt(evt.currentTarget.value.split('%')[0]) + this.editor.svgCanvas.setOpacity(val / 100) } + /** * @type {module} */ handlePalette (e) { - e.preventDefault(); + e.preventDefault() // shift key or right click for stroke - const { picker, color } = e.detail; + const { picker, color } = e.detail // Webkit-based browsers returned 'initial' here for no stroke - const paint = color === 'none' ? new jGraduate.Paint() : new jGraduate.Paint({ alpha: 100, solidColor: color.substr(1) }); + const paint = color === 'none' ? new jGraduate.Paint() : new jGraduate.Paint({ alpha: 100, solidColor: color.substr(1) }) if (picker === 'fill') { - $id('fill_color').setPaint(paint); + $id('fill_color').setPaint(paint) } else { - $id('stroke_color').setPaint(paint); + $id('stroke_color').setPaint(paint) } - this.editor.svgCanvas.setColor(picker, color); + this.editor.svgCanvas.setColor(picker, color) if (color !== 'none' && this.editor.svgCanvas.getPaintOpacity(picker) !== 1) { - this.editor.svgCanvas.setPaintOpacity(picker, 1.0); + this.editor.svgCanvas.setPaintOpacity(picker, 1.0) } - this.updateToolButtonState(); + this.updateToolButtonState() } + /** * @type {module} */ init () { // register actions for Bottom panel - const template = document.createElement('template'); - const { i18next } = this.editor; + const template = document.createElement('template') + const { i18next } = this.editor - // eslint-disable-next-line no-unsanitized/property - template.innerHTML = BottomPanelHtml; - this.editor.$svgEditor.append(template.content.cloneNode(true)); - $id('palette').addEventListener('change', this.handlePalette.bind(this)); - $id('palette').init(i18next); - const { curConfig } = this.editor.configObj; - $id('fill_color').setPaint(new jGraduate.Paint({ alpha: 100, solidColor: curConfig.initFill.color })); - $id('stroke_color').setPaint(new jGraduate.Paint({ alpha: 100, solidColor: curConfig.initStroke.color })); - $id('zoom').addEventListener('change', (e) => this.changeZoom.bind(this)(e.detail.value)); - $id('stroke_color').addEventListener('change', (evt) => this.handleColorPicker.bind(this)('stroke', evt)); - $id('fill_color').addEventListener('change', (evt) => this.handleColorPicker.bind(this)('fill', evt)); - $id('stroke_width').addEventListener('change', this.changeStrokeWidth.bind(this)); - $id('stroke_style').addEventListener('change', (evt) => this.handleStrokeAttr.bind(this)('stroke-dasharray', evt)); - $id('stroke_linejoin').addEventListener('change', (evt) => this.handleStrokeAttr.bind(this)('stroke-linejoin', evt)); - $id('stroke_linecap').addEventListener('change', (evt) => this.handleStrokeAttr.bind(this)('stroke-linecap', evt)); - $id('opacity').addEventListener('change', this.handleOpacity.bind(this)); - $id('fill_color').init(i18next); - $id('stroke_color').init(i18next); + template.innerHTML = BottomPanelHtml + this.editor.$svgEditor.append(template.content.cloneNode(true)) + $id('palette').addEventListener('change', this.handlePalette.bind(this)) + $id('palette').init(i18next) + const { curConfig } = this.editor.configObj + $id('fill_color').setPaint(new jGraduate.Paint({ alpha: 100, solidColor: curConfig.initFill.color })) + $id('stroke_color').setPaint(new jGraduate.Paint({ alpha: 100, solidColor: curConfig.initStroke.color })) + $id('zoom').addEventListener('change', (e) => this.changeZoom.bind(this)(e.detail.value)) + $id('stroke_color').addEventListener('change', (evt) => this.handleColorPicker.bind(this)('stroke', evt)) + $id('fill_color').addEventListener('change', (evt) => this.handleColorPicker.bind(this)('fill', evt)) + $id('stroke_width').addEventListener('change', this.changeStrokeWidth.bind(this)) + $id('stroke_style').addEventListener('change', (evt) => this.handleStrokeAttr.bind(this)('stroke-dasharray', evt)) + $id('stroke_linejoin').addEventListener('change', (evt) => this.handleStrokeAttr.bind(this)('stroke-linejoin', evt)) + $id('stroke_linecap').addEventListener('change', (evt) => this.handleStrokeAttr.bind(this)('stroke-linecap', evt)) + $id('opacity').addEventListener('change', this.handleOpacity.bind(this)) + $id('fill_color').init(i18next) + $id('stroke_color').init(i18next) } + /** * @type {module} */ updateColorpickers (apply) { - $id('fill_color').update(this.editor.svgCanvas, this.editor.selectedElement, apply); - $id('stroke_color').update(this.editor.svgCanvas, this.editor.selectedElement, apply); + $id('fill_color').update(this.editor.svgCanvas, this.editor.selectedElement, apply) + $id('stroke_color').update(this.editor.svgCanvas, this.editor.selectedElement, apply) } } -export default BottomPanel; +export default BottomPanel diff --git a/src/editor/panels/LayersPanel.js b/src/editor/panels/LayersPanel.js index 73e83edc..0230b817 100644 --- a/src/editor/panels/LayersPanel.js +++ b/src/editor/panels/LayersPanel.js @@ -1,7 +1,7 @@ -import SvgCanvas from "../../svgcanvas/svgcanvas.js"; -import LayersPanelHtml from './LayersPanel.html'; +import SvgCanvas from '../../svgcanvas/svgcanvas.js' +import LayersPanelHtml from './LayersPanel.html' -const { $id } = SvgCanvas; +const { $id } = SvgCanvas /** * @@ -10,119 +10,120 @@ class LayersPanel { /** * @param {PlainObject} editor */ - constructor(editor) { - this.updateContextPanel = editor.topPanel.updateContextPanel.bind(editor.topPanel); - this.editor = editor; + constructor (editor) { + this.updateContextPanel = editor.topPanel.updateContextPanel.bind(editor.topPanel) + this.editor = editor } /** * @param {PlainObject} e event * @returns {void} */ - lmenuFunc(e) { - const action = e?.detail?.trigger; + lmenuFunc (e) { + const action = e?.detail?.trigger switch (action) { - case "dupe": - this.cloneLayer(); - break; - case "delete": - this.deleteLayer(); - break; - case "merge_down": - this.mergeLayer(); - break; - case "merge_all": - this.editor.svgCanvas.mergeAllLayers(); - this.updateContextPanel(); - this.populateLayers(); - break; + case 'dupe': + this.cloneLayer() + break + case 'delete': + this.deleteLayer() + break + case 'merge_down': + this.mergeLayer() + break + case 'merge_all': + this.editor.svgCanvas.mergeAllLayers() + this.updateContextPanel() + this.populateLayers() + break } } - /** - * @returns {void} - */ - init() { - const template = document.createElement("template"); - const { i18next } = this.editor; - // eslint-disable-next-line no-unsanitized/property - template.innerHTML = LayersPanelHtml; - this.editor.$svgEditor.append(template.content.cloneNode(true)); - // layer menu added to DOM - const menuMore = document.createElement("se-cmenu-layers"); - menuMore.setAttribute("id", "se-cmenu-layers-more"); - menuMore.value = "layer_moreopts"; - menuMore.setAttribute("leftclick", true); - this.editor.$container.append(menuMore); - menuMore.init(i18next); - const menuLayerBox = document.createElement("se-cmenu-layers"); - menuLayerBox.setAttribute("id", "se-cmenu-layers-list"); - menuLayerBox.value = "layerlist"; - menuLayerBox.setAttribute("leftclick", false); - this.editor.$container.append(menuLayerBox); - menuLayerBox.init(i18next); - $id("layer_new").addEventListener("click", this.newLayer.bind(this)); - $id("layer_delete").addEventListener("click", this.deleteLayer.bind(this)); - $id("layer_up").addEventListener("click", () => this.moveLayer.bind(this)(-1)); - $id("layer_down").addEventListener("click", () => this.moveLayer.bind(this)(1)); - $id("layer_rename").addEventListener("click", this.layerRename.bind(this)); - $id("se-cmenu-layers-more").addEventListener("change", this.lmenuFunc.bind(this)); - $id("se-cmenu-layers-list").addEventListener("change", (e) => { this.lmenuFunc(e); }); - $id("sidepanel_handle").addEventListener("click", () => this.toggleSidePanel()); - this.toggleSidePanel(this.editor.configObj.curConfig.showlayers); - } - toggleSidePanel(displayFlag) { - if (displayFlag === undefined) { - this.editor.$svgEditor.classList.toggle('open'); - } else if (displayFlag) { - this.editor.$svgEditor.classList.add('open'); - } else { - this.editor.$svgEditor.classList.remove('open'); - } - } /** * @returns {void} */ - newLayer() { - let uniqName; - let i = this.editor.svgCanvas.getCurrentDrawing().getNumLayers(); + init () { + const template = document.createElement('template') + const { i18next } = this.editor + + template.innerHTML = LayersPanelHtml + this.editor.$svgEditor.append(template.content.cloneNode(true)) + // layer menu added to DOM + const menuMore = document.createElement('se-cmenu-layers') + menuMore.setAttribute('id', 'se-cmenu-layers-more') + menuMore.value = 'layer_moreopts' + menuMore.setAttribute('leftclick', true) + this.editor.$container.append(menuMore) + menuMore.init(i18next) + const menuLayerBox = document.createElement('se-cmenu-layers') + menuLayerBox.setAttribute('id', 'se-cmenu-layers-list') + menuLayerBox.value = 'layerlist' + menuLayerBox.setAttribute('leftclick', false) + this.editor.$container.append(menuLayerBox) + menuLayerBox.init(i18next) + $id('layer_new').addEventListener('click', this.newLayer.bind(this)) + $id('layer_delete').addEventListener('click', this.deleteLayer.bind(this)) + $id('layer_up').addEventListener('click', () => this.moveLayer.bind(this)(-1)) + $id('layer_down').addEventListener('click', () => this.moveLayer.bind(this)(1)) + $id('layer_rename').addEventListener('click', this.layerRename.bind(this)) + $id('se-cmenu-layers-more').addEventListener('change', this.lmenuFunc.bind(this)) + $id('se-cmenu-layers-list').addEventListener('change', (e) => { this.lmenuFunc(e) }) + $id('sidepanel_handle').addEventListener('click', () => this.toggleSidePanel()) + this.toggleSidePanel(this.editor.configObj.curConfig.showlayers) + } + + toggleSidePanel (displayFlag) { + if (displayFlag === undefined) { + this.editor.$svgEditor.classList.toggle('open') + } else if (displayFlag) { + this.editor.$svgEditor.classList.add('open') + } else { + this.editor.$svgEditor.classList.remove('open') + } + } + + /** + * @returns {void} + */ + newLayer () { + let uniqName + let i = this.editor.svgCanvas.getCurrentDrawing().getNumLayers() do { - uniqName = this.editor.i18next.t("layers.layer") + " " + ++i; - } while (this.editor.svgCanvas.getCurrentDrawing().hasLayer(uniqName)); + uniqName = this.editor.i18next.t('layers.layer') + ' ' + ++i + } while (this.editor.svgCanvas.getCurrentDrawing().hasLayer(uniqName)) const newName = prompt( this.editor.i18next.t('notification.enterUniqueLayerName'), uniqName - ); + ) if (!newName) { - return; + return } if (this.editor.svgCanvas.getCurrentDrawing().hasLayer(newName)) { - alert(this.editor.i18next.t('notification.dupeLayerName')); - return; + alert(this.editor.i18next.t('notification.dupeLayerName')) + return } - this.editor.svgCanvas.createLayer(newName); - this.updateContextPanel(); - this.populateLayers(); + this.editor.svgCanvas.createLayer(newName) + this.updateContextPanel() + this.populateLayers() } /** * * @returns {void} */ - deleteLayer() { + deleteLayer () { if (this.editor.svgCanvas.deleteCurrentLayer()) { - this.updateContextPanel(); - this.populateLayers(); + this.updateContextPanel() + this.populateLayers() // This matches what this.editor.svgCanvas does // 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) - const elements = document.querySelectorAll('#layerlist tr.layer'); - Array.prototype.forEach.call(elements, function(el){ - el.classList.remove('layersel'); - }); - document.querySelector('#layerlist tr.layer').classList.add('layersel'); - + const elements = document.querySelectorAll('#layerlist tr.layer') + Array.prototype.forEach.call(elements, function (el) { + el.classList.remove('layersel') + }) + document.querySelector('#layerlist tr.layer').classList.add('layersel') } } @@ -130,85 +131,85 @@ class LayersPanel { * * @returns {void} */ - cloneLayer() { + cloneLayer () { const name = - this.editor.svgCanvas.getCurrentDrawing().getCurrentLayerName() + " copy"; + this.editor.svgCanvas.getCurrentDrawing().getCurrentLayerName() + ' copy' const newName = prompt( this.editor.i18next.t('notification.enterUniqueLayerName'), name - ); + ) if (!newName) { - return; + return } if (this.editor.svgCanvas.getCurrentDrawing().hasLayer(newName)) { - alert(this.editor.i18next.t('notification.dupeLayerName')); - return; + alert(this.editor.i18next.t('notification.dupeLayerName')) + return } - this.editor.svgCanvas.cloneLayer(newName); - this.updateContextPanel(); - this.populateLayers(); + this.editor.svgCanvas.cloneLayer(newName) + this.updateContextPanel() + this.populateLayers() } - index(el) { - if (!el) return -1; - let i = 0; + index (el) { + if (!el) return -1 + let i = 0 do { - i++; - } while (el == el.previousElementSibling); - return i; + i++ + } while (el === el.previousElementSibling) + return i } /** * * @returns {void} */ - mergeLayer() { + mergeLayer () { if ( - (this.index(document.querySelector("#layerlist tr.layersel"))-1) === + (this.index(document.querySelector('#layerlist tr.layersel')) - 1) === this.editor.svgCanvas.getCurrentDrawing().getNumLayers() - 1 ) { - return; + return } - this.editor.svgCanvas.mergeLayer(); - this.updateContextPanel(); - this.populateLayers(); + this.editor.svgCanvas.mergeLayer() + this.updateContextPanel() + this.populateLayers() } /** * @param {Integer} pos * @returns {void} */ - moveLayer(pos) { - const total = this.editor.svgCanvas.getCurrentDrawing().getNumLayers(); + moveLayer (pos) { + const total = this.editor.svgCanvas.getCurrentDrawing().getNumLayers() - let curIndex = (this.index(document.querySelector("#layerlist tr.layersel"))-1); + let curIndex = (this.index(document.querySelector('#layerlist tr.layersel')) - 1) if (curIndex > 0 || curIndex < total - 1) { - curIndex += pos; - this.editor.svgCanvas.setCurrentLayerPosition(total - curIndex - 1); - this.populateLayers(); + curIndex += pos + this.editor.svgCanvas.setCurrentLayerPosition(total - curIndex - 1) + this.populateLayers() } } /** * @returns {void} */ - layerRename() { - const ele = document.querySelector("#layerlist tr.layersel td.layername"); - const oldName = (ele) ? ele.textContent : ''; - const newName = prompt(this.editor.i18next.t('notification.enterNewLayerName'), ""); + layerRename () { + const ele = document.querySelector('#layerlist tr.layersel td.layername') + const oldName = (ele) ? ele.textContent : '' + const newName = prompt(this.editor.i18next.t('notification.enterNewLayerName'), '') if (!newName) { - return; + return } if ( oldName === newName || this.editor.svgCanvas.getCurrentDrawing().hasLayer(newName) ) { - alert(this.editor.i18next.t('notification.layerHasThatName')); - return; + alert(this.editor.i18next.t('notification.layerHasThatName')) + return } - this.editor.svgCanvas.renameCurrentLayer(newName); - this.populateLayers(); + this.editor.svgCanvas.renameCurrentLayer(newName) + this.populateLayers() } /** @@ -217,12 +218,12 @@ class LayersPanel { * @param {string} [layerNameToHighlight] * @returns {void} */ - toggleHighlightLayer(layerNameToHighlight) { - let i; - const curNames = []; - const numLayers = this.editor.svgCanvas.getCurrentDrawing().getNumLayers(); + toggleHighlightLayer (layerNameToHighlight) { + let i + const curNames = [] + const numLayers = this.editor.svgCanvas.getCurrentDrawing().getNumLayers() for (i = 0; i < numLayers; i++) { - curNames[i] = this.editor.svgCanvas.getCurrentDrawing().getLayerName(i); + curNames[i] = this.editor.svgCanvas.getCurrentDrawing().getLayerName(i) } if (layerNameToHighlight) { @@ -230,89 +231,88 @@ class LayersPanel { if (curName !== layerNameToHighlight) { this.editor.svgCanvas .getCurrentDrawing() - .setLayerOpacity(curName, 0.5); + .setLayerOpacity(curName, 0.5) } - }); + }) } else { curNames.forEach((curName) => { - this.editor.svgCanvas.getCurrentDrawing().setLayerOpacity(curName, 1.0); - }); + this.editor.svgCanvas.getCurrentDrawing().setLayerOpacity(curName, 1.0) + }) } } /** * @returns {void} */ - populateLayers() { - this.editor.svgCanvas.clearSelection(); - const self = this; - const layerlist = $id("layerlist").querySelector('tbody'); - while(layerlist.firstChild) - layerlist.removeChild(layerlist.firstChild); + populateLayers () { + this.editor.svgCanvas.clearSelection() + const self = this + const layerlist = $id('layerlist').querySelector('tbody') + while (layerlist.firstChild) { layerlist.removeChild(layerlist.firstChild) } - $id("selLayerNames").setAttribute("options", ""); - const drawing = this.editor.svgCanvas.getCurrentDrawing(); - const currentLayerName = drawing.getCurrentLayerName(); - let layer = this.editor.svgCanvas.getCurrentDrawing().getNumLayers(); + $id('selLayerNames').setAttribute('options', '') + const drawing = this.editor.svgCanvas.getCurrentDrawing() + const currentLayerName = drawing.getCurrentLayerName() + let layer = this.editor.svgCanvas.getCurrentDrawing().getNumLayers() // we get the layers in the reverse z-order (the layer rendered on top is listed first) - let values = ""; - let text = ""; + let values = '' + let text = '' while (layer--) { - const name = drawing.getLayerName(layer); - const layerTr = document.createElement("tr"); - layerTr.className = (name === currentLayerName) ? 'layer layersel' : 'layer'; - const layerVis = document.createElement("td"); - layerVis.className = (!drawing.getLayerVisibility(name)) ? "layerinvis layervis" : 'layervis'; - const layerName = document.createElement("td"); - layerName.className = 'layername'; - layerName.textContent = name; - layerTr.appendChild(layerVis); - layerTr.appendChild(layerName); - layerlist.appendChild(layerTr); - values = (values) ? values + "::" + name : name; - text = (text) ? text + "," + name : name; + const name = drawing.getLayerName(layer) + const layerTr = document.createElement('tr') + layerTr.className = (name === currentLayerName) ? 'layer layersel' : 'layer' + const layerVis = document.createElement('td') + layerVis.className = (!drawing.getLayerVisibility(name)) ? 'layerinvis layervis' : 'layervis' + const layerName = document.createElement('td') + layerName.className = 'layername' + layerName.textContent = name + layerTr.appendChild(layerVis) + layerTr.appendChild(layerName) + layerlist.appendChild(layerTr) + values = (values) ? values + '::' + name : name + text = (text) ? text + ',' + name : name } - $id("selLayerNames").setAttribute("options", text); - $id("selLayerNames").setAttribute("values", values); + $id('selLayerNames').setAttribute('options', text) + $id('selLayerNames').setAttribute('values', values) // handle selection of layer - const nelements = $id('layerlist').querySelectorAll("td.layername"); - Array.from(nelements).forEach(function(element) { - element.addEventListener('mouseup', function(evt) { - const trElements = $id('layerlist').querySelectorAll("tr.layer"); - Array.from(trElements).forEach(function(element) { - element.classList.remove("layersel"); - }); - evt.currentTarget.parentNode.classList.add("layersel"); - self.editor.svgCanvas.setCurrentLayer(evt.currentTarget.textContent); - evt.preventDefault(); - }); + const nelements = $id('layerlist').querySelectorAll('td.layername') + Array.from(nelements).forEach(function (element) { + element.addEventListener('mouseup', function (evt) { + const trElements = $id('layerlist').querySelectorAll('tr.layer') + Array.from(trElements).forEach(function (element) { + element.classList.remove('layersel') + }) + evt.currentTarget.parentNode.classList.add('layersel') + self.editor.svgCanvas.setCurrentLayer(evt.currentTarget.textContent) + evt.preventDefault() + }) element.addEventListener('mouseup', (evt) => { - self.toggleHighlightLayer(evt.currentTarget.textContent); - }); + self.toggleHighlightLayer(evt.currentTarget.textContent) + }) element.addEventListener('mouseout', (_evt) => { - self.toggleHighlightLayer(); - }); - }); - const elements = $id('layerlist').querySelectorAll("td.layervis"); - Array.from(elements).forEach(function(element) { - element.addEventListener('click', function(evt) { - const ele = evt.currentTarget.parentNode.querySelector("td.layername"); - const name = (ele)? ele.textContent : ''; - const vis = evt.currentTarget.classList.contains("layerinvis"); - self.editor.svgCanvas.setLayerVisibility(name, vis); - evt.currentTarget.classList.toggle("layerinvis"); - }); - }); + self.toggleHighlightLayer() + }) + }) + const elements = $id('layerlist').querySelectorAll('td.layervis') + Array.from(elements).forEach(function (element) { + element.addEventListener('click', function (evt) { + const ele = evt.currentTarget.parentNode.querySelector('td.layername') + const name = (ele) ? ele.textContent : '' + const vis = evt.currentTarget.classList.contains('layerinvis') + self.editor.svgCanvas.setLayerVisibility(name, vis) + evt.currentTarget.classList.toggle('layerinvis') + }) + }) // if there were too few rows, let's add a few to make it not so lonely - let num = 5 - $id('layerlist').querySelectorAll("tr.layer").length; + let num = 5 - $id('layerlist').querySelectorAll('tr.layer').length while (num-- > 0) { // TODO: there must a better way to do this - const tlayer = document.createElement("tr"); - tlayer.innerHTML = '_'; - layerlist.append(tlayer); + const tlayer = document.createElement('tr') + tlayer.innerHTML = '_' + layerlist.append(tlayer) } } } -export default LayersPanel; +export default LayersPanel diff --git a/src/editor/panels/LeftPanel.js b/src/editor/panels/LeftPanel.js index 9c860302..f73adb24 100644 --- a/src/editor/panels/LeftPanel.js +++ b/src/editor/panels/LeftPanel.js @@ -1,7 +1,7 @@ -import SvgCanvas from "../../svgcanvas/svgcanvas.js"; -import leftPanelHTML from './LeftPanel.html'; +import SvgCanvas from '../../svgcanvas/svgcanvas.js' +import leftPanelHTML from './LeftPanel.html' -const { $id, $qa } = SvgCanvas; +const { $id, $qa } = SvgCanvas /* * register actions for left panel @@ -13,9 +13,10 @@ class LeftPanel { /** * @param {PlainObject} editor svgedit handler */ - constructor(editor) { - this.editor = editor; + constructor (editor) { + this.editor = editor } + /** * This is a common function used when a tool has been clicked (chosen). * It does several common things: @@ -25,15 +26,15 @@ class LeftPanel { * @param {string|Element} button The DOM element or string selector representing the toolbar button * @returns {boolean} Whether the button was disabled or not */ - updateLeftPanel(button) { - if (button.disabled) return false; + updateLeftPanel (button) { + if (button.disabled) return false // remove the pressed state on other(s) button(s) - $qa("#tools_left *[pressed]").forEach((b) => { - b.pressed = false; - }); + $qa('#tools_left *[pressed]').forEach((b) => { + b.pressed = false + }) // pressed state for the clicked button - $id(button).pressed = true; - return true; + $id(button).pressed = true + return true } /** @@ -42,10 +43,10 @@ class LeftPanel { * @function module:SVGEditor.clickSelect * @returns {void} */ - clickSelect() { - if (this.updateLeftPanel("tool_select")) { - this.editor.workarea.style.cursor = "auto"; - this.editor.svgCanvas.setMode("select"); + clickSelect () { + if (this.updateLeftPanel('tool_select')) { + this.editor.workarea.style.cursor = 'auto' + this.editor.svgCanvas.setMode('select') } } @@ -53,9 +54,9 @@ class LeftPanel { * * @returns {void} */ - clickFHPath() { - if (this.updateLeftPanel("tool_fhpath")) { - this.editor.svgCanvas.setMode("fhpath"); + clickFHPath () { + if (this.updateLeftPanel('tool_fhpath')) { + this.editor.svgCanvas.setMode('fhpath') } } @@ -63,9 +64,9 @@ class LeftPanel { * * @returns {void} */ - clickLine() { - if (this.updateLeftPanel("tool_line")) { - this.editor.svgCanvas.setMode("line"); + clickLine () { + if (this.updateLeftPanel('tool_line')) { + this.editor.svgCanvas.setMode('line') } } @@ -73,9 +74,9 @@ class LeftPanel { * * @returns {void} */ - clickSquare() { - if (this.updateLeftPanel("tool_square")) { - this.editor.svgCanvas.setMode("square"); + clickSquare () { + if (this.updateLeftPanel('tool_square')) { + this.editor.svgCanvas.setMode('square') } } @@ -83,9 +84,9 @@ class LeftPanel { * * @returns {void} */ - clickRect() { - if (this.updateLeftPanel("tool_rect")) { - this.editor.svgCanvas.setMode("rect"); + clickRect () { + if (this.updateLeftPanel('tool_rect')) { + this.editor.svgCanvas.setMode('rect') } } @@ -93,9 +94,9 @@ class LeftPanel { * * @returns {void} */ - clickFHRect() { - if (this.updateLeftPanel("tool_fhrect")) { - this.editor.svgCanvas.setMode("fhrect"); + clickFHRect () { + if (this.updateLeftPanel('tool_fhrect')) { + this.editor.svgCanvas.setMode('fhrect') } } @@ -103,9 +104,9 @@ class LeftPanel { * * @returns {void} */ - clickCircle() { - if (this.updateLeftPanel("tool_circle")) { - this.editor.svgCanvas.setMode("circle"); + clickCircle () { + if (this.updateLeftPanel('tool_circle')) { + this.editor.svgCanvas.setMode('circle') } } @@ -113,9 +114,9 @@ class LeftPanel { * * @returns {void} */ - clickEllipse() { - if (this.updateLeftPanel("tool_ellipse")) { - this.editor.svgCanvas.setMode("ellipse"); + clickEllipse () { + if (this.updateLeftPanel('tool_ellipse')) { + this.editor.svgCanvas.setMode('ellipse') } } @@ -123,9 +124,9 @@ class LeftPanel { * * @returns {void} */ - clickFHEllipse() { - if (this.updateLeftPanel("tool_fhellipse")) { - this.editor.svgCanvas.setMode("fhellipse"); + clickFHEllipse () { + if (this.updateLeftPanel('tool_fhellipse')) { + this.editor.svgCanvas.setMode('fhellipse') } } @@ -133,9 +134,9 @@ class LeftPanel { * * @returns {void} */ - clickImage() { - if (this.updateLeftPanel("tool_image")) { - this.editor.svgCanvas.setMode("image"); + clickImage () { + if (this.updateLeftPanel('tool_image')) { + this.editor.svgCanvas.setMode('image') } } @@ -143,10 +144,10 @@ class LeftPanel { * * @returns {void} */ - clickZoom() { - if (this.updateLeftPanel("tool_zoom")) { - this.editor.svgCanvas.setMode("zoom"); - this.editor.workarea.style.cursor = this.editor.zoomInIcon; + clickZoom () { + if (this.updateLeftPanel('tool_zoom')) { + this.editor.svgCanvas.setMode('zoom') + this.editor.workarea.style.cursor = this.editor.zoomInIcon } } @@ -154,10 +155,10 @@ class LeftPanel { * * @returns {void} */ - dblclickZoom() { - if (this.updateLeftPanel("tool_zoom")) { - this.editor.zoomImage(); - this.clickSelect(); + dblclickZoom () { + if (this.updateLeftPanel('tool_zoom')) { + this.editor.zoomImage() + this.clickSelect() } } @@ -165,9 +166,9 @@ class LeftPanel { * * @returns {void} */ - clickText() { - if (this.updateLeftPanel("tool_text")) { - this.editor.svgCanvas.setMode("text"); + clickText () { + if (this.updateLeftPanel('tool_text')) { + this.editor.svgCanvas.setMode('text') } } @@ -175,49 +176,49 @@ class LeftPanel { * * @returns {void} */ - clickPath() { - if (this.updateLeftPanel("tool_path")) { - this.editor.svgCanvas.setMode("path"); + clickPath () { + if (this.updateLeftPanel('tool_path')) { + this.editor.svgCanvas.setMode('path') } } + /** * @type {module} */ - add(id, handler) { - $id(id).addEventListener("click", () => { + add (id, handler) { + $id(id).addEventListener('click', () => { if (this.updateLeftPanel(id)) { - handler(); + handler() } - }); + }) } + /** * @type {module} */ - init() { - + init () { // add Left panel - const template = document.createElement("template"); - // eslint-disable-next-line no-unsanitized/property - template.innerHTML = leftPanelHTML; - this.editor.$svgEditor.append(template.content.cloneNode(true)); + const template = document.createElement('template') + template.innerHTML = leftPanelHTML + this.editor.$svgEditor.append(template.content.cloneNode(true)) // register actions for left panel - $id("tool_select").addEventListener("click", this.clickSelect.bind(this)); - $id("tool_fhpath").addEventListener("click", this.clickFHPath.bind(this)); - $id("tool_text").addEventListener("click", this.clickText.bind(this)); - $id("tool_image").addEventListener("click", this.clickImage.bind(this)); - $id("tool_zoom").addEventListener("click", this.clickZoom.bind(this)); - $id("tool_zoom").addEventListener("dblclick", this.dblclickZoom.bind(this)); - $id("tool_path").addEventListener("click", this.clickPath.bind(this)); - $id("tool_line").addEventListener("click", this.clickLine.bind(this)); + $id('tool_select').addEventListener('click', this.clickSelect.bind(this)) + $id('tool_fhpath').addEventListener('click', this.clickFHPath.bind(this)) + $id('tool_text').addEventListener('click', this.clickText.bind(this)) + $id('tool_image').addEventListener('click', this.clickImage.bind(this)) + $id('tool_zoom').addEventListener('click', this.clickZoom.bind(this)) + $id('tool_zoom').addEventListener('dblclick', this.dblclickZoom.bind(this)) + $id('tool_path').addEventListener('click', this.clickPath.bind(this)) + $id('tool_line').addEventListener('click', this.clickLine.bind(this)) // flyout - $id("tool_rect").addEventListener("click", this.clickRect.bind(this)); - $id("tool_square").addEventListener("click", this.clickSquare.bind(this)); - $id("tool_fhrect").addEventListener("click", this.clickFHRect.bind(this)); - $id("tool_ellipse").addEventListener("click", this.clickEllipse.bind(this)); - $id("tool_circle").addEventListener("click", this.clickCircle.bind(this)); - $id("tool_fhellipse").addEventListener("click", this.clickFHEllipse.bind(this)); + $id('tool_rect').addEventListener('click', this.clickRect.bind(this)) + $id('tool_square').addEventListener('click', this.clickSquare.bind(this)) + $id('tool_fhrect').addEventListener('click', this.clickFHRect.bind(this)) + $id('tool_ellipse').addEventListener('click', this.clickEllipse.bind(this)) + $id('tool_circle').addEventListener('click', this.clickCircle.bind(this)) + $id('tool_fhellipse').addEventListener('click', this.clickFHEllipse.bind(this)) } } -export default LeftPanel; +export default LeftPanel diff --git a/src/editor/panels/TopPanel.js b/src/editor/panels/TopPanel.js index 3a21cdca..571e74dc 100644 --- a/src/editor/panels/TopPanel.js +++ b/src/editor/panels/TopPanel.js @@ -1,11 +1,11 @@ /* eslint-disable max-len */ /* globals seAlert */ -import SvgCanvas from "../../svgcanvas/svgcanvas.js"; -import { isValidUnit, getTypeMap, convertUnit } from "../../common/units.js"; -import topPanelHTML from './TopPanel.html'; +import SvgCanvas from '../../svgcanvas/svgcanvas.js' +import { isValidUnit, getTypeMap, convertUnit } from '../../common/units.js' +import topPanelHTML from './TopPanel.html' -const { $qa, $id } = SvgCanvas; +const { $qa, $id } = SvgCanvas /* * register actions for left panel @@ -17,39 +17,44 @@ class TopPanel { /** * @param {PlainObject} editor svgedit handler */ - constructor(editor) { - this.editor = editor; + constructor (editor) { + this.editor = editor } + /** * @type {module} */ - displayTool(className) { + displayTool (className) { // default display is 'none' so removing the property will make the panel visible - $qa(`.${className}`).map( (el) => el.style.removeProperty('display')); + $qa(`.${className}`).map((el) => el.style.removeProperty('display')) } + /** * @type {module} */ - hideTool(className) { - $qa(`.${className}`).map( (el) => el.style.display = 'none'); + hideTool (className) { + $qa(`.${className}`).forEach((el) => { el.style.display = 'none' }) } + /** * @type {module} */ - get selectedElement() { - return this.editor.selectedElement; + get selectedElement () { + return this.editor.selectedElement } + /** * @type {module} */ - get multiselected() { - return this.editor.multiselected; + get multiselected () { + return this.editor.multiselected } + /** * @type {module} */ - get path() { - return this.editor.svgCanvas.pathActions; + get path () { + return this.editor.svgCanvas.pathActions } /** @@ -58,21 +63,21 @@ class TopPanel { * @param {boolean} changeElem * @returns {void} */ - setStrokeOpt(opt, changeElem) { - const { id } = opt; - const bits = id.split('_'); - const [ pre, val ] = bits; + setStrokeOpt (opt, changeElem) { + const { id } = opt + const bits = id.split('_') + const [pre, val] = bits if (changeElem) { - this.svgCanvas.setStrokeAttr('stroke-' + pre, val); + this.svgCanvas.setStrokeAttr('stroke-' + pre, val) } - opt.classList.add('current'); + opt.classList.add('current') const elements = Array.prototype.filter.call(opt.parentNode.children, function (child) { - return child !== opt; - }); + return child !== opt + }) Array.from(elements).forEach(function (element) { - element.classList.remove('current'); - }); + element.classList.remove('current') + }) } /** @@ -81,407 +86,411 @@ class TopPanel { * context panel. * @returns {void} */ - update() { - let i; let len; + update () { + let i; let len if (this.selectedElement) { switch (this.selectedElement.tagName) { - case "use": - case "image": - case "foreignObject": - break; - case "g": - case "a": { + case 'use': + case 'image': + case 'foreignObject': + break + case 'g': + case 'a': { // Look for common styles - const childs = this.selectedElement.getElementsByTagName("*"); - let gWidth = null; - for (i = 0, len = childs.length; i < len; i++) { - const swidth = childs[i].getAttribute("stroke-width"); + const childs = this.selectedElement.getElementsByTagName('*') + let gWidth = null + for (i = 0, len = childs.length; i < len; i++) { + const swidth = childs[i].getAttribute('stroke-width') - if (i === 0) { - gWidth = swidth; - } else if (gWidth !== swidth) { - gWidth = null; + if (i === 0) { + gWidth = swidth + } else if (gWidth !== swidth) { + gWidth = null + } + } + + $id('stroke_width').value = (gWidth === null ? '' : gWidth) + this.editor.bottomPanel.updateColorpickers(true) + break + } + default: { + this.editor.bottomPanel.updateColorpickers(true) + + $id('stroke_width').value = this.selectedElement.getAttribute('stroke-width') || 1 + $id('stroke_style').value = this.selectedElement.getAttribute('stroke-dasharray') || 'none' + $id('stroke_style').setAttribute('value', $id('stroke_style').value) + + let attr = + this.selectedElement.getAttribute('stroke-linejoin') || 'miter' + + if ($id('linejoin_' + attr)) { + this.setStrokeOpt($id('linejoin_' + attr)) + $id('stroke_linejoin').setAttribute('value', attr) + } + + attr = this.selectedElement.getAttribute('stroke-linecap') || 'butt' + if ($id('linecap_' + attr)) { + this.setStrokeOpt($id('linecap_' + attr)) + $id('stroke_linecap').setAttribute('value', attr) } } - - $id("stroke_width").value = (gWidth === null ? "" : gWidth); - this.editor.bottomPanel.updateColorpickers(true); - break; - } - default: { - this.editor.bottomPanel.updateColorpickers(true); - - $id("stroke_width").value = this.selectedElement.getAttribute("stroke-width") || 1; - $id("stroke_style").value = this.selectedElement.getAttribute("stroke-dasharray") || "none"; - $id("stroke_style").setAttribute("value", $id("stroke_style").value); - - let attr = - this.selectedElement.getAttribute("stroke-linejoin") || "miter"; - - if ($id("linejoin_" + attr)) { - this.setStrokeOpt($id("linejoin_" + attr)); - $id("stroke_linejoin").setAttribute("value", attr); - } - - attr = this.selectedElement.getAttribute("stroke-linecap") || "butt"; - if ($id("linecap_" + attr)) { - this.setStrokeOpt($id("linecap_" + attr)); - $id("stroke_linecap").setAttribute("value", attr); - } - } } } // All elements including image and group have opacity if (this.selectedElement) { const opacPerc = - (this.selectedElement.getAttribute("opacity") || 1.0) * 100; - $id("opacity").value = opacPerc; - $id("elem_id").value = this.selectedElement.id; - $id("elem_class").value = this.selectedElement.getAttribute("class") ?? ""; + (this.selectedElement.getAttribute('opacity') || 1.0) * 100 + $id('opacity').value = opacPerc + $id('elem_id').value = this.selectedElement.id + $id('elem_class').value = this.selectedElement.getAttribute('class') ?? '' } - this.editor.bottomPanel.updateToolButtonState(); + this.editor.bottomPanel.updateToolButtonState() } + /** * @param {PlainObject} [opts={}] * @param {boolean} [opts.cancelDeletes=false] * @returns {void} Resolves to `undefined` */ - promptImgURL({ cancelDeletes = false } = {}) { - let curhref = this.editor.svgCanvas.getHref(this.editor.selectedElement); - curhref = curhref.startsWith("data:") ? "" : curhref; + promptImgURL ({ cancelDeletes = false } = {}) { + let curhref = this.editor.svgCanvas.getHref(this.editor.selectedElement) + curhref = curhref.startsWith('data:') ? '' : curhref const url = prompt( this.editor.i18next.t('notification.enterNewImgURL'), curhref - ); + ) if (url) { - this.setImageURL(url); + this.setImageURL(url) } else if (cancelDeletes) { - this.editor.svgCanvas.deleteSelectedElements(); + this.editor.svgCanvas.deleteSelectedElements() } } + /** * Updates the context panel tools based on the selected element. * @returns {void} */ - updateContextPanel() { - let elem = this.editor.selectedElement; + updateContextPanel () { + let elem = this.editor.selectedElement // If element has just been deleted, consider it null if (!elem?.parentNode) { - elem = null; + elem = null } const currentLayerName = this.editor.svgCanvas .getCurrentDrawing() - .getCurrentLayerName(); - const currentMode = this.editor.svgCanvas.getMode(); + .getCurrentLayerName() + const currentMode = this.editor.svgCanvas.getMode() const unit = - this.editor.configObj.curConfig.baseUnit !== "px" + this.editor.configObj.curConfig.baseUnit !== 'px' ? this.editor.configObj.curConfig.baseUnit - : null; + : null - const isNode = currentMode === "pathedit"; // elem ? (elem.id && elem.id.startsWith('pathpointgrip')) : false; - const menuItems = document.getElementById("se-cmenu_canvas"); - this.hideTool("selected_panel"); - this.hideTool("multiselected_panel"); - this.hideTool("g_panel"); - this.hideTool("rect_panel"); - this.hideTool("circle_panel"); - this.hideTool("ellipse_panel"); - this.hideTool("line_panel"); - this.hideTool("text_panel"); - this.hideTool("image_panel"); - this.hideTool("container_panel"); - this.hideTool("use_panel"); - this.hideTool("a_panel"); - this.hideTool("xy_panel"); + const isNode = currentMode === 'pathedit' // elem ? (elem.id && elem.id.startsWith('pathpointgrip')) : false; + const menuItems = document.getElementById('se-cmenu_canvas') + this.hideTool('selected_panel') + this.hideTool('multiselected_panel') + this.hideTool('g_panel') + this.hideTool('rect_panel') + this.hideTool('circle_panel') + this.hideTool('ellipse_panel') + this.hideTool('line_panel') + this.hideTool('text_panel') + this.hideTool('image_panel') + this.hideTool('container_panel') + this.hideTool('use_panel') + this.hideTool('a_panel') + this.hideTool('xy_panel') if (elem) { - const elname = elem.nodeName; + const elname = elem.nodeName - const angle = this.editor.svgCanvas.getRotationAngle(elem); - $id("angle").value = angle; + const angle = this.editor.svgCanvas.getRotationAngle(elem) + $id('angle').value = angle - const blurval = this.editor.svgCanvas.getBlur(elem) * 10; - $id("blur").value = blurval; + const blurval = this.editor.svgCanvas.getBlur(elem) * 10 + $id('blur').value = blurval if ( this.editor.svgCanvas.addedNew && - elname === "image" && - this.editor.svgCanvas.getMode() === "image" && - !this.editor.svgCanvas.getHref(elem).startsWith("data:") + elname === 'image' && + this.editor.svgCanvas.getMode() === 'image' && + !this.editor.svgCanvas.getHref(elem).startsWith('data:') ) { - /* await */ this.promptImgURL({ cancelDeletes: true }); + /* await */ this.promptImgURL({ cancelDeletes: true }) } - if (!isNode && currentMode !== "pathedit") { - this.displayTool("selected_panel"); + if (!isNode && currentMode !== 'pathedit') { + this.displayTool('selected_panel') // Elements in this array already have coord fields - if ([ "line", "circle", "ellipse" ].includes(elname)) { - this.hideTool("xy_panel"); + if (['line', 'circle', 'ellipse'].includes(elname)) { + this.hideTool('xy_panel') } else { - let x; let y; + let x; let y // Get BBox vals for g, polyline and path - if ([ "g", "polyline", "path" ].includes(elname)) { - const bb = this.editor.svgCanvas.getStrokedBBox([ elem ]); + if (['g', 'polyline', 'path'].includes(elname)) { + const bb = this.editor.svgCanvas.getStrokedBBox([elem]) if (bb) { - ({ x, y } = bb); + ({ x, y } = bb) } } else { - x = elem.getAttribute("x"); - y = elem.getAttribute("y"); + x = elem.getAttribute('x') + y = elem.getAttribute('y') } if (unit) { - x = convertUnit(x); - y = convertUnit(y); + x = convertUnit(x) + y = convertUnit(y) } - $id("selected_x").value = (x || 0); - $id("selected_y").value = (y || 0); - this.displayTool("xy_panel"); + $id('selected_x').value = (x || 0) + $id('selected_y').value = (y || 0) + this.displayTool('xy_panel') } // Elements in this array cannot be converted to a path if ([ - "image", - "text", - "path", - "g", - "use" + 'image', + 'text', + 'path', + 'g', + 'use' ].includes(elname)) { - this.hideTool("tool_topath"); + this.hideTool('tool_topath') } else { - this.displayTool("tool_topath"); + this.displayTool('tool_topath') } - if (elname === "path") { - this.displayTool("tool_reorient"); + if (elname === 'path') { + this.displayTool('tool_reorient') } else { - this.hideTool("tool_reorient"); + this.hideTool('tool_reorient') } - $id("tool_reorient").disabled = (angle === 0); + $id('tool_reorient').disabled = (angle === 0) } else { - const point = this.path.getNodePoint(); - $id("tool_add_subpath").pressed = false; - (!this.path.canDeleteNodes) ? $id("tool_node_delete").classList.add("disabled") : $id("tool_node_delete").classList.remove("disabled"); + const point = this.path.getNodePoint() + $id('tool_add_subpath').pressed = false; + (!this.path.canDeleteNodes) ? $id('tool_node_delete').classList.add('disabled') : $id('tool_node_delete').classList.remove('disabled') // Show open/close button based on selected point // setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path'); if (point) { - const segType = $id("seg_type"); + const segType = $id('seg_type') if (unit) { - point.x = convertUnit(point.x); - point.y = convertUnit(point.y); + point.x = convertUnit(point.x) + point.y = convertUnit(point.y) } - $id("path_node_x").value = (point.x); - $id("path_node_y").value = (point.y); + $id('path_node_x').value = (point.x) + $id('path_node_y').value = (point.y) if (point.type) { - segType.value = (point.type); - segType.removeAttribute("disabled"); + segType.value = (point.type) + segType.removeAttribute('disabled') } else { - segType.value = 4; - segType.setAttribute("disabled", "disabled"); + segType.value = 4 + segType.setAttribute('disabled', 'disabled') } } - return; + return } // update contextual tools here const panels = { g: [], a: [], - rect: [ "rx", "width", "height" ], - image: [ "width", "height" ], - circle: [ "cx", "cy", "r" ], - ellipse: [ "cx", "cy", "rx", "ry" ], - line: [ "x1", "y1", "x2", "y2" ], + rect: ['rx', 'width', 'height'], + image: ['width', 'height'], + circle: ['cx', 'cy', 'r'], + ellipse: ['cx', 'cy', 'rx', 'ry'], + line: ['x1', 'y1', 'x2', 'y2'], text: [], use: [] - }; + } - const { tagName } = elem; + const { tagName } = elem - let linkHref = null; - if (tagName === "a") { - linkHref = this.editor.svgCanvas.getHref(elem); - this.displayTool("g_panel"); + let linkHref = null + if (tagName === 'a') { + linkHref = this.editor.svgCanvas.getHref(elem) + this.displayTool('g_panel') } // siblings if (elem.parentNode) { const selements = Array.prototype.filter.call(elem.parentNode.children, function (child) { - return child !== elem; - }); - if (elem.parentNode.tagName === "a" && !selements.length) { - this.displayTool("a_panel"); - linkHref = this.editor.svgCanvas.getHref(elem.parentNode); + return child !== elem + }) + if (elem.parentNode.tagName === 'a' && !selements.length) { + this.displayTool('a_panel') + linkHref = this.editor.svgCanvas.getHref(elem.parentNode) } } // Hide/show the make_link buttons if (linkHref) { - this.displayTool('tool_make_link'); - this.displayTool('tool_make_link_multi'); - $id("link_url").value = linkHref; + this.displayTool('tool_make_link') + this.displayTool('tool_make_link_multi') + $id('link_url').value = linkHref } else { - this.hideTool('tool_make_link'); - this.hideTool('tool_make_link_multi'); + this.hideTool('tool_make_link') + this.hideTool('tool_make_link_multi') } if (panels[tagName]) { - const curPanel = panels[tagName]; - this.displayTool(tagName + "_panel"); + const curPanel = panels[tagName] + this.displayTool(tagName + '_panel') curPanel.forEach((item) => { - let attrVal = elem.getAttribute(item); - if (this.editor.configObj.curConfig.baseUnit !== "px" && elem[item]) { - const bv = elem[item].baseVal.value; - attrVal = convertUnit(bv); + let attrVal = elem.getAttribute(item) + if (this.editor.configObj.curConfig.baseUnit !== 'px' && elem[item]) { + const bv = elem[item].baseVal.value + attrVal = convertUnit(bv) } - $id(`${tagName}_${item}`).value = attrVal || 0; - }); + $id(`${tagName}_${item}`).value = attrVal || 0 + }) - if (tagName === "text") { - this.displayTool("text_panel"); - $id("tool_italic").pressed = this.editor.svgCanvas.getItalic(); - $id("tool_bold").pressed = this.editor.svgCanvas.getBold(); - $id("tool_font_family").setAttribute("value", elem.getAttribute("font-family")); - $id("font_size").value = elem.getAttribute("font-size"); - $id("text").value = elem.textContent; - const textAnchorStart = $id("tool_text_anchor_start"); - const textAnchorMiddle = $id("tool_text_anchor_middle"); - const textAnchorEnd = $id("tool_text_anchor_end"); - switch (elem.getAttribute("text-anchor")) { - case "start": - textAnchorStart.pressed = true; - textAnchorMiddle.pressed = false; - textAnchorEnd.pressed = false; - break; - case "middle": - textAnchorStart.pressed = false; - textAnchorMiddle.pressed = true; - textAnchorEnd.pressed = false; - break; - case "end": - textAnchorStart.pressed = false; - textAnchorMiddle.pressed = false; - textAnchorEnd.pressed = true; - break; + if (tagName === 'text') { + this.displayTool('text_panel') + $id('tool_italic').pressed = this.editor.svgCanvas.getItalic() + $id('tool_bold').pressed = this.editor.svgCanvas.getBold() + $id('tool_font_family').setAttribute('value', elem.getAttribute('font-family')) + $id('font_size').value = elem.getAttribute('font-size') + $id('text').value = elem.textContent + const textAnchorStart = $id('tool_text_anchor_start') + const textAnchorMiddle = $id('tool_text_anchor_middle') + const textAnchorEnd = $id('tool_text_anchor_end') + switch (elem.getAttribute('text-anchor')) { + case 'start': + textAnchorStart.pressed = true + textAnchorMiddle.pressed = false + textAnchorEnd.pressed = false + break + case 'middle': + textAnchorStart.pressed = false + textAnchorMiddle.pressed = true + textAnchorEnd.pressed = false + break + case 'end': + textAnchorStart.pressed = false + textAnchorMiddle.pressed = false + textAnchorEnd.pressed = true + break } if (this.editor.svgCanvas.addedNew) { // Timeout needed for IE9 setTimeout(() => { - $id("text").focus(); - $id("text").select(); - }, 100); + $id('text').focus() + $id('text').select() + }, 100) } // text } else if ( - tagName === "image" && - this.editor.svgCanvas.getMode() === "image" + tagName === 'image' && + this.editor.svgCanvas.getMode() === 'image' ) { this.editor.svgCanvas.setImageURL( this.editor.svgCanvas.getHref(elem) - ); + ) // image - } else if (tagName === "g" || tagName === "use") { - this.displayTool("container_panel"); - const title = this.editor.svgCanvas.getTitle(); - const label = $id("g_title"); - label.value = title; - $id("g_title").disabled = (tagName === "use"); + } else if (tagName === 'g' || tagName === 'use') { + this.displayTool('container_panel') + const title = this.editor.svgCanvas.getTitle() + const label = $id('g_title') + label.value = title + $id('g_title').disabled = (tagName === 'use') } } menuItems.setAttribute( - (tagName === "g" ? "en" : "dis") + "ablemenuitems", - "#ungroup" - ); + (tagName === 'g' ? 'en' : 'dis') + 'ablemenuitems', + '#ungroup' + ) menuItems.setAttribute( - (tagName === "g" || !this.multiselected ? "dis" : "en") + - "ablemenuitems", - "#group" - ); + (tagName === 'g' || !this.multiselected ? 'dis' : 'en') + + 'ablemenuitems', + '#group' + ) // if (!isNullish(elem)) } else if (this.multiselected) { - this.displayTool("multiselected_panel"); - menuItems.setAttribute("enablemenuitems", "#group"); - menuItems.setAttribute("disablemenuitems", "#ungroup"); + this.displayTool('multiselected_panel') + menuItems.setAttribute('enablemenuitems', '#group') + menuItems.setAttribute('disablemenuitems', '#ungroup') } else { menuItems.setAttribute( - "disablemenuitems", - "#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back" - ); + 'disablemenuitems', + '#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back' + ) } // update history buttons - $id("tool_undo").disabled = - this.editor.svgCanvas.undoMgr.getUndoStackSize() === 0; - $id("tool_redo").disabled = - this.editor.svgCanvas.undoMgr.getRedoStackSize() === 0; + $id('tool_undo').disabled = + this.editor.svgCanvas.undoMgr.getUndoStackSize() === 0 + $id('tool_redo').disabled = + this.editor.svgCanvas.undoMgr.getRedoStackSize() === 0 - this.editor.svgCanvas.addedNew = false; + this.editor.svgCanvas.addedNew = false if ((elem && !isNode) || this.multiselected) { // update the selected elements' layer - $id("selLayerNames").removeAttribute("disabled"); - $id("selLayerNames").value = currentLayerName; - $id("selLayerNames").setAttribute("value", currentLayerName); + $id('selLayerNames').removeAttribute('disabled') + $id('selLayerNames').value = currentLayerName + $id('selLayerNames').setAttribute('value', currentLayerName) // Enable regular menu options - const canCMenu = document.getElementById("se-cmenu_canvas"); + const canCMenu = document.getElementById('se-cmenu_canvas') canCMenu.setAttribute( - "enablemenuitems", - "#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back" - ); + 'enablemenuitems', + '#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back' + ) } else { - $id("selLayerNames").setAttribute("disabled", "disabled"); + $id('selLayerNames').setAttribute('disabled', 'disabled') } } + /** * @param {Event} [e] Not used. * @param {boolean} forSaving * @returns {void} */ - showSourceEditor(e, forSaving) { - const $editorDialog = document.getElementById("se-svg-editor-dialog"); - if ($editorDialog.getAttribute("dialog") === "open") return; - const origSource = this.editor.svgCanvas.getSvgString(); - $editorDialog.setAttribute("dialog", "open"); - $editorDialog.setAttribute("value", origSource); - $editorDialog.setAttribute("copysec", Boolean(forSaving)); - $editorDialog.setAttribute("applysec", !forSaving); + showSourceEditor (e, forSaving) { + const $editorDialog = document.getElementById('se-svg-editor-dialog') + if ($editorDialog.getAttribute('dialog') === 'open') return + const origSource = this.editor.svgCanvas.getSvgString() + $editorDialog.setAttribute('dialog', 'open') + $editorDialog.setAttribute('value', origSource) + $editorDialog.setAttribute('copysec', Boolean(forSaving)) + $editorDialog.setAttribute('applysec', !forSaving) } - /** - * - * @returns {void} - */ - clickWireframe() { - $id("tool_wireframe").pressed = !$id("tool_wireframe").pressed; - this.editor.workarea.classList.toggle("wireframe"); - const wfRules = $id("wireframe_rules"); - if (!wfRules) { - const fcRules = document.createElement('style'); - fcRules.setAttribute('id', 'wireframe_rules'); - document.getElementsByTagName("head")[0].appendChild(fcRules); - } else { - while (wfRules.firstChild) - wfRules.removeChild(wfRules.firstChild); - } - this.editor.updateWireFrame(); - } /** * * @returns {void} */ - clickUndo() { - const { undoMgr, textActions } = this.editor.svgCanvas; + clickWireframe () { + $id('tool_wireframe').pressed = !$id('tool_wireframe').pressed + this.editor.workarea.classList.toggle('wireframe') + + const wfRules = $id('wireframe_rules') + if (!wfRules) { + const fcRules = document.createElement('style') + fcRules.setAttribute('id', 'wireframe_rules') + document.getElementsByTagName('head')[0].appendChild(fcRules) + } else { + while (wfRules.firstChild) { wfRules.removeChild(wfRules.firstChild) } + } + this.editor.updateWireFrame() + } + + /** + * + * @returns {void} + */ + clickUndo () { + const { undoMgr, textActions } = this.editor.svgCanvas if (undoMgr.getUndoStackSize() > 0) { - undoMgr.undo(); - this.editor.layersPanel.populateLayers(); + undoMgr.undo() + this.editor.layersPanel.populateLayers() if (this.editor.svgCanvas.getMode() === 'textedit') { - textActions.clear(); + textActions.clear() } } } @@ -490,53 +499,55 @@ class TopPanel { * * @returns {void} */ - clickRedo() { - const { undoMgr } = this.editor.svgCanvas; + clickRedo () { + const { undoMgr } = this.editor.svgCanvas if (undoMgr.getRedoStackSize() > 0) { - undoMgr.redo(); - this.editor.layersPanel.populateLayers(); + undoMgr.redo() + this.editor.layersPanel.populateLayers() } } + /** * @type {module} */ - changeRectRadius(e) { - this.editor.svgCanvas.setRectRadius(e.target.value); + changeRectRadius (e) { + this.editor.svgCanvas.setRectRadius(e.target.value) } /** * @type {module} */ - changeFontSize(e) { - this.editor.svgCanvas.setFontSize(e.target.value); + changeFontSize (e) { + this.editor.svgCanvas.setFontSize(e.target.value) } /** * @type {module} */ - changeRotationAngle(e) { + changeRotationAngle (e) { this.editor.svgCanvas.setRotationAngle(e.target.value); - (Number.parseInt(e.target.value) === 0) ? $id("tool_reorient").classList.add("disabled") : $id("tool_reorient").classList.remove("disabled"); + (Number.parseInt(e.target.value) === 0) ? $id('tool_reorient').classList.add('disabled') : $id('tool_reorient').classList.remove('disabled') } /** * @param {PlainObject} e * @returns {void} */ - changeBlur(e) { - this.editor.svgCanvas.setBlur(e.target.value / 10, true); + changeBlur (e) { + this.editor.svgCanvas.setBlur(e.target.value / 10, true) } + /** * * @returns {void} */ - clickGroup() { + clickGroup () { // group if (this.editor.multiselected) { - this.editor.svgCanvas.groupSelectedElements(); + this.editor.svgCanvas.groupSelectedElements() // ungroup } else if (this.editor.selectedElement) { - this.editor.svgCanvas.ungroupSelectedElement(); + this.editor.svgCanvas.ungroupSelectedElement() } } @@ -544,125 +555,130 @@ class TopPanel { * * @returns {void} */ - clickClone() { - this.editor.svgCanvas.cloneSelectedElements(20, 20); + clickClone () { + this.editor.svgCanvas.cloneSelectedElements(20, 20) } /** * @param {PlainObject} evt * @returns {void} */ - clickAlignEle(evt) { - this.editor.svgCanvas.alignSelectedElements(evt.detail.value, "page"); + clickAlignEle (evt) { + this.editor.svgCanvas.alignSelectedElements(evt.detail.value, 'page') } /** * @param {string} pos indicate the alignment relative to top, bottom, middle etc.. * @returns {void} */ - clickAlign(pos) { - let value = $id("tool_align_relative").value; - if (value === "") { - value = "selected"; + clickAlign (pos) { + let value = $id('tool_align_relative').value + if (value === '') { + value = 'selected' } - this.editor.svgCanvas.alignSelectedElements(pos, value); + this.editor.svgCanvas.alignSelectedElements(pos, value) } + /** * * @type {module} */ - attrChanger(e) { - const attr = e.target.getAttribute("data-attr"); - let val = e.target.value; - const valid = isValidUnit(attr, val, this.selectedElement); + attrChanger (e) { + const attr = e.target.getAttribute('data-attr') + let val = e.target.value + const valid = isValidUnit(attr, val, this.selectedElement) if (!valid) { - e.target.value = this.selectedElement.getAttribute(attr); - alert(this.editor.i18next.t('notification.invalidAttrValGiven')); - return false; + e.target.value = this.selectedElement.getAttribute(attr) + alert(this.editor.i18next.t('notification.invalidAttrValGiven')) + return false } - if (attr !== "id" && attr !== "class") { + if (attr !== 'id' && attr !== 'class') { if (isNaN(val)) { - val = this.editor.svgCanvas.convertToNum(attr, val); - } else if (this.editor.configObj.curConfig.baseUnit !== "px") { + val = this.editor.svgCanvas.convertToNum(attr, val) + } else if (this.editor.configObj.curConfig.baseUnit !== 'px') { // Convert unitless value to one with given unit - const unitData = getTypeMap(); + const unitData = getTypeMap() if ( this.editor.selectedElement[attr] || - this.editor.svgCanvas.getMode() === "pathedit" || - attr === "x" || - attr === "y" + this.editor.svgCanvas.getMode() === 'pathedit' || + attr === 'x' || + attr === 'y' ) { - val *= unitData[this.editor.configObj.curConfig.baseUnit]; + val *= unitData[this.editor.configObj.curConfig.baseUnit] } } } // if the user is changing the id, then de-select the element first // change the ID, then re-select it with the new ID - if (attr === "id") { - const elem = this.editor.selectedElement; - this.editor.svgCanvas.clearSelection(); - elem.id = val; - this.editor.svgCanvas.addToSelection([ elem ], true); + if (attr === 'id') { + const elem = this.editor.selectedElement + this.editor.svgCanvas.clearSelection() + elem.id = val + this.editor.svgCanvas.addToSelection([elem], true) } else { - this.editor.svgCanvas.changeSelectedAttribute(attr, val); + this.editor.svgCanvas.changeSelectedAttribute(attr, val) } - return true; + return true } + /** * * @returns {void} */ - convertToPath() { + convertToPath () { if (this.editor.selectedElement) { - this.editor.svgCanvas.convertToPath(); + this.editor.svgCanvas.convertToPath() } } + /** * * @returns {void} */ - reorientPath() { + reorientPath () { if (this.editor.selectedElement) { - this.path.reorient(); + this.path.reorient() } } + /** * * @returns {void} Resolves to `undefined` */ - makeHyperlink() { + makeHyperlink () { if (this.editor.selectedElement || this.multiselected) { const url = prompt( this.editor.i18next.t('notification.enterNewLinkURL'), - "http://" - ); + 'http://' + ) if (url) { - this.editor.svgCanvas.makeHyperlink(url); + this.editor.svgCanvas.makeHyperlink(url) } } } + /** * * @returns {void} */ - linkControlPoints() { - $id("tool_node_link").pressed = ($id("tool_node_link").pressed) ? false : true; - const linked = ($id("tool_node_link").pressed) ? true : false; - this.path.linkControlPoints(linked); + linkControlPoints () { + $id('tool_node_link').pressed = !($id('tool_node_link').pressed) + const linked = !!($id('tool_node_link').pressed) + this.path.linkControlPoints(linked) } /** * * @returns {void} */ - clonePathNode() { + clonePathNode () { if (this.path.getNodePoint()) { - this.path.clonePathNode(); + this.path.clonePathNode() } } @@ -670,9 +686,9 @@ class TopPanel { * * @returns {void} */ - deletePathNode() { + deletePathNode () { if (this.path.getNodePoint()) { - this.path.deletePathNode(); + this.path.deletePathNode() } } @@ -680,38 +696,30 @@ class TopPanel { * * @returns {void} */ - addSubPath() { - const button = $id("tool_add_subpath"); - const sp = !button.classList.contains("pressed"); - button.pressed = sp; + addSubPath () { + const button = $id('tool_add_subpath') + const sp = !button.classList.contains('pressed') + button.pressed = sp // button.toggleClass('push_button_pressed tool_button'); - this.path.addSubPath(sp); + this.path.addSubPath(sp) } /** * * @returns {void} */ - opencloseSubPath() { - this.path.opencloseSubPath(); + opencloseSubPath () { + this.path.opencloseSubPath() } + /** * Delete is a contextual tool that only appears in the ribbon if * an element has been selected. * @returns {void} */ - deleteSelected() { + deleteSelected () { if (this.editor.selectedElement || this.editor.multiselected) { - this.editor.svgCanvas.deleteSelectedElements(); - } - } - /** - * - * @returns {void} - */ - moveToTopSelected() { - if (this.editor.selectedElement) { - this.editor.svgCanvas.moveToTopSelectedElement(); + this.editor.svgCanvas.deleteSelectedElements() } } @@ -719,29 +727,40 @@ class TopPanel { * * @returns {void} */ - moveToBottomSelected() { + moveToTopSelected () { if (this.editor.selectedElement) { - this.editor.svgCanvas.moveToBottomSelectedElement(); + this.editor.svgCanvas.moveToTopSelectedElement() } } + /** * - * @returns {false} + * @returns {void} */ - clickBold() { - this.editor.svgCanvas.setBold(!this.editor.svgCanvas.getBold()); - this.updateContextPanel(); - return false; + moveToBottomSelected () { + if (this.editor.selectedElement) { + this.editor.svgCanvas.moveToBottomSelectedElement() + } } /** * * @returns {false} */ - clickItalic() { - this.editor.svgCanvas.setItalic(!this.editor.svgCanvas.getItalic()); - this.updateContextPanel(); - return false; + clickBold () { + this.editor.svgCanvas.setBold(!this.editor.svgCanvas.getBold()) + this.updateContextPanel() + return false + } + + /** + * + * @returns {false} + */ + clickItalic () { + this.editor.svgCanvas.setItalic(!this.editor.svgCanvas.getItalic()) + this.updateContextPanel() + return false } /** @@ -749,159 +768,160 @@ class TopPanel { * @param {string} value "start","end" or "middle" * @returns {false} */ - clickTextAnchor(value) { - this.editor.svgCanvas.setTextAnchor(value); - this.updateContextPanel(); - return false; + clickTextAnchor (value) { + this.editor.svgCanvas.setTextAnchor(value) + this.updateContextPanel() + return false } + /** * Set a selected image's URL. * @function module:SVGthis.setImageURL * @param {string} url * @returns {void} */ - setImageURL(url) { - const { editor } = this; + setImageURL (url) { + const { editor } = this if (!url) { - url = editor.defaultImageURL; + url = editor.defaultImageURL } - editor.svgCanvas.setImageURL(url); - $id("image_url").value = url; + editor.svgCanvas.setImageURL(url) + $id('image_url').value = url if (url.startsWith('data:')) { // data URI found - this.hideTool("image_url"); + this.hideTool('image_url') } else { // regular URL - const promised = editor.svgCanvas.embedImage(url); + const promised = editor.svgCanvas.embedImage(url) // eslint-disable-next-line promise/catch-or-return promised // eslint-disable-next-line promise/always-return .then(() => { // switch into "select" mode if we've clicked on an element - editor.svgCanvas.setMode('select'); - editor.svgCanvas.selectOnly(editor.svgCanvas.getSelectedElements(), true); + editor.svgCanvas.setMode('select') + editor.svgCanvas.selectOnly(editor.svgCanvas.getSelectedElements(), true) }, (error) => { - console.error("error =", error); - seAlert(editor.i18next.t('tools.no_embed')); - editor.svgCanvas.deleteSelectedElements(); - }); - this.displayTool("image_url"); + console.error('error =', error) + seAlert(editor.i18next.t('tools.no_embed')) + editor.svgCanvas.deleteSelectedElements() + }) + this.displayTool('image_url') } } + /** * @param {boolean} editmode * @param {module:svgcanvas.SvgCanvas#event:selected} elems * @returns {void} */ - togglePathEditMode(editMode, elems) { + togglePathEditMode (editMode, elems) { if (editMode) { - this.displayTool('path_node_panel'); + this.displayTool('path_node_panel') } else { - this.hideTool('path_node_panel'); + this.hideTool('path_node_panel') } if (editMode) { // Change select icon - $id('tool_path').pressed = false; - $id('tool_select').pressed = true; - $id('tool_select').setAttribute('src', `select_node.svg`); - this.editor.multiselected = false; + $id('tool_path').pressed = false + $id('tool_select').pressed = true + $id('tool_select').setAttribute('src', 'select_node.svg') + this.editor.multiselected = false if (elems.length) { - this.editor.selectedElement = elems[0]; + this.editor.selectedElement = elems[0] } } else { setTimeout(() => { - $id('tool_select').setAttribute('src', `select.svg`); - }, 1000); + $id('tool_select').setAttribute('src', 'select.svg') + }, 1000) } } /** * @type {module} */ - init() { + init () { // add Top panel - const template = document.createElement("template"); - const { i18next } = this.editor; - // eslint-disable-next-line no-unsanitized/property - template.innerHTML = topPanelHTML; - this.editor.$svgEditor.append(template.content.cloneNode(true)); + const template = document.createElement('template') + const { i18next } = this.editor + template.innerHTML = topPanelHTML + this.editor.$svgEditor.append(template.content.cloneNode(true)) // svg editor source dialoag added to DOM const newSeEditorDialog = document.createElement( - "se-svg-source-editor-dialog" - ); - newSeEditorDialog.setAttribute("id", "se-svg-editor-dialog"); - this.editor.$container.append(newSeEditorDialog); - newSeEditorDialog.init(i18next); - $id("tool_link_url").setAttribute("title", i18next.t('tools.set_link_url')); + 'se-svg-source-editor-dialog' + ) + newSeEditorDialog.setAttribute('id', 'se-svg-editor-dialog') + this.editor.$container.append(newSeEditorDialog) + newSeEditorDialog.init(i18next) + $id('tool_link_url').setAttribute('title', i18next.t('tools.set_link_url')) // register action to top panel buttons - $id("tool_source").addEventListener("click", this.showSourceEditor.bind(this)); - $id("tool_wireframe").addEventListener("click", this.clickWireframe.bind(this)); - $id("tool_undo").addEventListener("click", this.clickUndo.bind(this)); - $id("tool_redo").addEventListener("click", this.clickRedo.bind(this)); - $id("tool_clone").addEventListener("click", this.clickClone.bind(this)); - $id("tool_clone_multi").addEventListener("click", this.clickClone.bind(this)); - $id("tool_delete").addEventListener("click", this.deleteSelected.bind(this)); - $id("tool_delete_multi").addEventListener("click", this.deleteSelected.bind(this)); - $id("tool_move_top").addEventListener("click", this.moveToTopSelected.bind(this)); - $id("tool_move_bottom").addEventListener("click", this.moveToBottomSelected.bind(this)); - $id("tool_topath").addEventListener("click", this.convertToPath.bind(this)); - $id("tool_make_link").addEventListener("click", this.makeHyperlink.bind(this)); - $id("tool_make_link_multi").addEventListener("click", this.makeHyperlink.bind(this)); - $id("tool_reorient").addEventListener("click", this.reorientPath.bind(this)); - $id("tool_group_elements").addEventListener("click", this.clickGroup.bind(this)); - $id("tool_position").addEventListener("change", (evt) => this.clickAlignEle.bind(this)(evt)); - $id("tool_align_left").addEventListener("click", () => this.clickAlign.bind(this)("left")); - $id("tool_align_right").addEventListener("click", () => this.clickAlign.bind(this)("right")); - $id("tool_align_center").addEventListener("click", () => this.clickAlign.bind(this)("center")); - $id("tool_align_top").addEventListener("click", () => this.clickAlign.bind(this)("top")); - $id("tool_align_bottom").addEventListener("click", () => this.clickAlign.bind(this)("bottom")); - $id("tool_align_middle").addEventListener("click", () => this.clickAlign.bind(this)("middle")); - $id("tool_node_clone").addEventListener("click", this.clonePathNode.bind(this)); - $id("tool_node_delete").addEventListener("click", this.deletePathNode.bind(this)); - $id("tool_openclose_path").addEventListener("click", this.opencloseSubPath.bind(this)); - $id("tool_add_subpath").addEventListener("click", this.addSubPath.bind(this)); - $id("tool_node_link").addEventListener("click", this.linkControlPoints.bind(this)); - $id("angle").addEventListener("change", this.changeRotationAngle.bind(this)); - $id("blur").addEventListener("change", this.changeBlur.bind(this)); - $id("rect_rx").addEventListener("change", this.changeRectRadius.bind(this)); - $id("font_size").addEventListener("change", this.changeFontSize.bind(this)); - $id("tool_ungroup").addEventListener("click", this.clickGroup.bind(this)); - $id("tool_bold").addEventListener("click", this.clickBold.bind(this)); - $id("tool_italic").addEventListener("click", this.clickItalic.bind(this)); - $id("tool_text_anchor_start").addEventListener("click", () => this.clickTextAnchor.bind(this)("start")); - $id("tool_text_anchor_middle").addEventListener("click", () => this.clickTextAnchor.bind(this)("middle")); - $id("tool_text_anchor_end").addEventListener("click", () => this.clickTextAnchor.bind(this)("end")); - $id("tool_unlink_use").addEventListener("click", this.clickGroup.bind(this)); - $id('image_url').addEventListener('change', (evt) => { this.setImageURL(evt.currentTarget.value);}); + $id('tool_source').addEventListener('click', this.showSourceEditor.bind(this)) + $id('tool_wireframe').addEventListener('click', this.clickWireframe.bind(this)) + $id('tool_undo').addEventListener('click', this.clickUndo.bind(this)) + $id('tool_redo').addEventListener('click', this.clickRedo.bind(this)) + $id('tool_clone').addEventListener('click', this.clickClone.bind(this)) + $id('tool_clone_multi').addEventListener('click', this.clickClone.bind(this)) + $id('tool_delete').addEventListener('click', this.deleteSelected.bind(this)) + $id('tool_delete_multi').addEventListener('click', this.deleteSelected.bind(this)) + $id('tool_move_top').addEventListener('click', this.moveToTopSelected.bind(this)) + $id('tool_move_bottom').addEventListener('click', this.moveToBottomSelected.bind(this)) + $id('tool_topath').addEventListener('click', this.convertToPath.bind(this)) + $id('tool_make_link').addEventListener('click', this.makeHyperlink.bind(this)) + $id('tool_make_link_multi').addEventListener('click', this.makeHyperlink.bind(this)) + $id('tool_reorient').addEventListener('click', this.reorientPath.bind(this)) + $id('tool_group_elements').addEventListener('click', this.clickGroup.bind(this)) + $id('tool_position').addEventListener('change', (evt) => this.clickAlignEle.bind(this)(evt)) + $id('tool_align_left').addEventListener('click', () => this.clickAlign.bind(this)('left')) + $id('tool_align_right').addEventListener('click', () => this.clickAlign.bind(this)('right')) + $id('tool_align_center').addEventListener('click', () => this.clickAlign.bind(this)('center')) + $id('tool_align_top').addEventListener('click', () => this.clickAlign.bind(this)('top')) + $id('tool_align_bottom').addEventListener('click', () => this.clickAlign.bind(this)('bottom')) + $id('tool_align_middle').addEventListener('click', () => this.clickAlign.bind(this)('middle')) + $id('tool_node_clone').addEventListener('click', this.clonePathNode.bind(this)) + $id('tool_node_delete').addEventListener('click', this.deletePathNode.bind(this)) + $id('tool_openclose_path').addEventListener('click', this.opencloseSubPath.bind(this)) + $id('tool_add_subpath').addEventListener('click', this.addSubPath.bind(this)) + $id('tool_node_link').addEventListener('click', this.linkControlPoints.bind(this)) + $id('angle').addEventListener('change', this.changeRotationAngle.bind(this)) + $id('blur').addEventListener('change', this.changeBlur.bind(this)) + $id('rect_rx').addEventListener('change', this.changeRectRadius.bind(this)) + $id('font_size').addEventListener('change', this.changeFontSize.bind(this)) + $id('tool_ungroup').addEventListener('click', this.clickGroup.bind(this)) + $id('tool_bold').addEventListener('click', this.clickBold.bind(this)) + $id('tool_italic').addEventListener('click', this.clickItalic.bind(this)) + $id('tool_text_anchor_start').addEventListener('click', () => this.clickTextAnchor.bind(this)('start')) + $id('tool_text_anchor_middle').addEventListener('click', () => this.clickTextAnchor.bind(this)('middle')) + $id('tool_text_anchor_end').addEventListener('click', () => this.clickTextAnchor.bind(this)('end')) + $id('tool_unlink_use').addEventListener('click', this.clickGroup.bind(this)) + $id('image_url').addEventListener('change', (evt) => { this.setImageURL(evt.currentTarget.value) }); // all top panel attributes [ - "elem_id", - "elem_class", - "circle_cx", - "circle_cy", - "circle_r", - "ellipse_cx", - "ellipse_cy", - "ellipse_rx", - "ellipse_ry", - "selected_x", - "selected_y", - "rect_width", - "rect_height", - "line_x1", - "line_x2", - "line_y1", - "line_y2", - "image_width", - "image_height", - "path_node_x", - "path_node_y" + 'elem_id', + 'elem_class', + 'circle_cx', + 'circle_cy', + 'circle_r', + 'ellipse_cx', + 'ellipse_cy', + 'ellipse_rx', + 'ellipse_ry', + 'selected_x', + 'selected_y', + 'rect_width', + 'rect_height', + 'line_x1', + 'line_x2', + 'line_y1', + 'line_y2', + 'image_width', + 'image_height', + 'path_node_x', + 'path_node_y' ].forEach((attrId) => - $id(attrId).addEventListener("change", this.attrChanger.bind(this)) - ); + $id(attrId).addEventListener('change', this.attrChanger.bind(this)) + ) } } -export default TopPanel; +export default TopPanel diff --git a/src/editor/touch.js b/src/editor/touch.js index d08cfb2f..b716b8df 100644 --- a/src/editor/touch.js +++ b/src/editor/touch.js @@ -5,18 +5,18 @@ * @returns {void} */ function touchHandler (ev) { - const { changedTouches } = ev; - const first = changedTouches[0]; + const { changedTouches } = ev + const first = changedTouches[0] - let type = ''; + let type = '' switch (ev.type) { - case 'touchstart': type = 'mousedown'; break; - case 'touchmove': type = 'mousemove'; break; - case 'touchend': type = 'mouseup'; break; - default: return; + case 'touchstart': type = 'mousedown'; break + case 'touchmove': type = 'mousemove'; break + case 'touchend': type = 'mouseup'; break + default: return } - const { screenX, screenY, clientX, clientY } = first; + const { screenX, screenY, clientX, clientY } = first const simulatedEvent = new MouseEvent(type, { // Event interface bubbles: true, @@ -25,7 +25,10 @@ function touchHandler (ev) { view: window, detail: 1, // click count // MouseEvent interface (customized) - screenX, screenY, clientX, clientY, + screenX, + screenY, + clientX, + clientY, // MouseEvent interface (defaults) - these could be removed ctrlKey: false, altKey: false, @@ -33,14 +36,14 @@ function touchHandler (ev) { metaKey: false, button: 0, // main button (usually left) relatedTarget: null - }); + }) if (changedTouches.length < 2) { - first.target.dispatchEvent(simulatedEvent); - ev.preventDefault(); + first.target.dispatchEvent(simulatedEvent) + ev.preventDefault() } } -document.addEventListener('touchstart', touchHandler, true); -document.addEventListener('touchmove', touchHandler, true); -document.addEventListener('touchend', touchHandler, true); -document.addEventListener('touchcancel', touchHandler, true); +document.addEventListener('touchstart', touchHandler, true) +document.addEventListener('touchmove', touchHandler, true) +document.addEventListener('touchend', touchHandler, true) +document.addEventListener('touchcancel', touchHandler, true) diff --git a/src/svgcanvas/blur-event.js b/src/svgcanvas/blur-event.js index 01bddad1..039a875d 100644 --- a/src/svgcanvas/blur-event.js +++ b/src/svgcanvas/blur-event.js @@ -5,7 +5,7 @@ * @copyright 2011 Jeff Schiller */ -let svgCanvas = null; +let svgCanvas = null /** * @function module:blur.init @@ -13,8 +13,8 @@ let svgCanvas = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; -}; + svgCanvas = canvas +} /** * Sets the `stdDeviation` blur value on the selected element without being undoable. @@ -23,41 +23,41 @@ export const init = function (canvas) { * @returns {void} */ export const setBlurNoUndo = function (val) { - const selectedElements = svgCanvas.getSelectedElements(); + const selectedElements = svgCanvas.getSelectedElements() if (!svgCanvas.getFilter()) { - svgCanvas.setBlur(val); - return; + svgCanvas.setBlur(val) + return } if (val === 0) { // Don't change the StdDev, as that will hide the element. // Instead, just remove the value for "filter" - svgCanvas.changeSelectedAttributeNoUndoMethod('filter', ''); - svgCanvas.setFilterHidden(true); + svgCanvas.changeSelectedAttributeNoUndoMethod('filter', '') + svgCanvas.setFilterHidden(true) } else { - const elem = selectedElements[0]; + const elem = selectedElements[0] if (svgCanvas.getFilterHidden()) { - svgCanvas.changeSelectedAttributeNoUndoMethod('filter', 'url(#' + elem.id + '_blur)'); + svgCanvas.changeSelectedAttributeNoUndoMethod('filter', 'url(#' + elem.id + '_blur)') } if (svgCanvas.isWebkit()) { - elem.removeAttribute('filter'); - elem.setAttribute('filter', 'url(#' + elem.id + '_blur)'); + elem.removeAttribute('filter') + elem.setAttribute('filter', 'url(#' + elem.id + '_blur)') } - const filter = svgCanvas.getFilter(); - svgCanvas.changeSelectedAttributeNoUndoMethod('stdDeviation', val, [ filter.firstChild ]); - svgCanvas.setBlurOffsets(filter, val); + const filter = svgCanvas.getFilter() + svgCanvas.changeSelectedAttributeNoUndoMethod('stdDeviation', val, [filter.firstChild]) + svgCanvas.setBlurOffsets(filter, val) } -}; +} /** * * @returns {void} */ function finishChange () { - const bCmd = svgCanvas.undoMgr.finishUndoableChange(); - svgCanvas.getCurCommand().addSubCommand(bCmd); - svgCanvas.addCommandToHistory(svgCanvas.getCurCommand()); - svgCanvas.setCurCommand(null); - svgCanvas.setFilter(null); + const bCmd = svgCanvas.undoMgr.finishUndoableChange() + svgCanvas.getCurCommand().addSubCommand(bCmd) + svgCanvas.addCommandToHistory(svgCanvas.getCurCommand()) + svgCanvas.setCurCommand(null) + svgCanvas.setFilter(null) } /** @@ -76,15 +76,15 @@ export const setBlurOffsets = function (filterElem, stdDev) { y: '-50%', width: '200%', height: '200%' - }, 100); + }, 100) // Removing these attributes hides text in Chrome (see Issue 579) } else if (!svgCanvas.isWebkit()) { - filterElem.removeAttribute('x'); - filterElem.removeAttribute('y'); - filterElem.removeAttribute('width'); - filterElem.removeAttribute('height'); + filterElem.removeAttribute('x') + filterElem.removeAttribute('y') + filterElem.removeAttribute('width') + filterElem.removeAttribute('height') } -}; +} /** * Adds/updates the blur filter to the selected element. @@ -96,64 +96,66 @@ export const setBlurOffsets = function (filterElem, stdDev) { export const setBlur = function (val, complete) { const { InsertElementCommand, ChangeElementCommand, BatchCommand - } = svgCanvas.history; + } = svgCanvas.history - const selectedElements = svgCanvas.getSelectedElements(); + const selectedElements = svgCanvas.getSelectedElements() if (svgCanvas.getCurCommand()) { - finishChange(); - return; + finishChange() + return } // Looks for associated blur, creates one if not found - const elem = selectedElements[0]; - const elemId = elem.id; - svgCanvas.setFilter(svgCanvas.getElem(elemId + '_blur')); + const elem = selectedElements[0] + const elemId = elem.id + svgCanvas.setFilter(svgCanvas.getElem(elemId + '_blur')) - val -= 0; + val -= 0 - const batchCmd = new BatchCommand(); + const batchCmd = new BatchCommand() // Blur found! if (svgCanvas.getFilter()) { if (val === 0) { - svgCanvas.setFilter(null); + svgCanvas.setFilter(null) } } else { // Not found, so create - const newblur = svgCanvas.addSVGElemensFromJson({ element: 'feGaussianBlur', + const newblur = svgCanvas.addSVGElemensFromJson({ + element: 'feGaussianBlur', attr: { in: 'SourceGraphic', stdDeviation: val } - }); + }) - svgCanvas.setFilter(svgCanvas.addSVGElemensFromJson({ element: 'filter', + svgCanvas.setFilter(svgCanvas.addSVGElemensFromJson({ + element: 'filter', attr: { id: elemId + '_blur' } - })); - svgCanvas.getFilter().append(newblur); - svgCanvas.findDefs().append(svgCanvas.getFilter()); + })) + svgCanvas.getFilter().append(newblur) + svgCanvas.findDefs().append(svgCanvas.getFilter()) - batchCmd.addSubCommand(new InsertElementCommand(svgCanvas.getFilter())); + batchCmd.addSubCommand(new InsertElementCommand(svgCanvas.getFilter())) } - const changes = { filter: elem.getAttribute('filter') }; + const changes = { filter: elem.getAttribute('filter') } if (val === 0) { - elem.removeAttribute('filter'); - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - return; + elem.removeAttribute('filter') + batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)) + return } - svgCanvas.changeSelectedAttribute('filter', 'url(#' + elemId + '_blur)'); - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - svgCanvas.setBlurOffsets(svgCanvas.getFilter(), val); - const filter = svgCanvas.getFilter(); - svgCanvas.setCurCommand(batchCmd); - svgCanvas.undoMgr.beginUndoableChange('stdDeviation', [ filter ? filter.firstChild : null ]); + svgCanvas.changeSelectedAttribute('filter', 'url(#' + elemId + '_blur)') + batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)) + svgCanvas.setBlurOffsets(svgCanvas.getFilter(), val) + const filter = svgCanvas.getFilter() + svgCanvas.setCurCommand(batchCmd) + svgCanvas.undoMgr.beginUndoableChange('stdDeviation', [filter ? filter.firstChild : null]) if (complete) { - svgCanvas.setBlurNoUndo(val); - finishChange(); + svgCanvas.setBlurNoUndo(val) + finishChange() } -}; +} diff --git a/src/svgcanvas/clear.js b/src/svgcanvas/clear.js index dd51b01f..5fc186bf 100644 --- a/src/svgcanvas/clear.js +++ b/src/svgcanvas/clear.js @@ -4,9 +4,9 @@ * @license MIT * @copyright 2011 Jeff Schiller */ -import { NS } from './namespaces.js'; +import { NS } from './namespaces.js' -let svgCanvas = null; +let svgCanvas = null /** * @function module:clear.init @@ -14,31 +14,30 @@ let svgCanvas = null; * @returns {void} */ export const init = (canvas) => { - svgCanvas = canvas; -}; + svgCanvas = canvas +} export const clearSvgContentElementInit = () => { - const curConfig = svgCanvas.getCurConfig(); - const { dimensions } = curConfig; - const el = svgCanvas.getSvgContent(); + const curConfig = svgCanvas.getCurConfig() + const { dimensions } = curConfig + const el = svgCanvas.getSvgContent() // empty - while(el.firstChild) - el.removeChild(el.firstChild); + while (el.firstChild) { el.removeChild(el.firstChild) } // TODO: Clear out all other attributes first? - const pel = svgCanvas.getSvgRoot(); - el.setAttribute('id', 'svgcontent'); - el.setAttribute('width', dimensions[0]); - el.setAttribute('height', dimensions[1]); - el.setAttribute('x', dimensions[0]); - el.setAttribute('y', dimensions[1]); - el.setAttribute('overflow', curConfig.show_outside_canvas ? 'visible' : 'hidden'); - el.setAttribute('xmlns', NS.SVG); - el.setAttribute('xmlns:se', NS.SE); - el.setAttribute('xmlns:xlink', NS.XLINK); - pel.appendChild(el); + const pel = svgCanvas.getSvgRoot() + el.setAttribute('id', 'svgcontent') + el.setAttribute('width', dimensions[0]) + el.setAttribute('height', dimensions[1]) + el.setAttribute('x', dimensions[0]) + el.setAttribute('y', dimensions[1]) + el.setAttribute('overflow', curConfig.show_outside_canvas ? 'visible' : 'hidden') + el.setAttribute('xmlns', NS.SVG) + el.setAttribute('xmlns:se', NS.SE) + el.setAttribute('xmlns:xlink', NS.XLINK) + pel.appendChild(el) // TODO: make this string optional and set by the client - const comment = svgCanvas.getDOMDocument().createComment(' Created with SVG-edit - https://github.com/SVG-Edit/svgedit'); - svgCanvas.getSvgContent().append(comment); -}; + const comment = svgCanvas.getDOMDocument().createComment(' Created with SVG-edit - https://github.com/SVG-Edit/svgedit') + svgCanvas.getSvgContent().append(comment) +} diff --git a/src/svgcanvas/coords.js b/src/svgcanvas/coords.js index 167f3945..c55619e8 100644 --- a/src/svgcanvas/coords.js +++ b/src/svgcanvas/coords.js @@ -6,16 +6,16 @@ import { snapToGrid, assignAttributes, getBBox, getRefElem, findDefs -} from './utilities.js'; +} from './utilities.js' import { transformPoint, transformListToTransform, matrixMultiply, transformBox -} from './math.js'; +} from './math.js' // this is how we map paths to our preferred relative segment types const pathMap = [ 0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a', 'H', 'h', 'V', 'v', 'S', 's', 'T', 't' -]; +] /** * @interface module:coords.EditorContext @@ -33,7 +33,7 @@ const pathMap = [ * @returns {SVGSVGElement} */ -let svgCanvas = null; +let svgCanvas = null /** * @function module:coords.init @@ -41,8 +41,8 @@ let svgCanvas = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; -}; + svgCanvas = canvas +} /** * Applies coordinate changes to an element based on the given matrix. @@ -50,253 +50,253 @@ export const init = function (canvas) { * @type {module:path.EditorContext#remapElement} */ export const remapElement = function (selected, changes, m) { - const remap = (x, y) => transformPoint(x, y, m); - const scalew = (w) => m.a * w; - const scaleh = (h) => m.d * h; - const doSnapping = svgCanvas.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg'; + const remap = (x, y) => transformPoint(x, y, m) + const scalew = (w) => m.a * w + const scaleh = (h) => m.d * h + const doSnapping = svgCanvas.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg' const finishUp = () => { if (doSnapping) { - Object.entries(changes).forEach(([ o, value ]) => { - changes[o] = snapToGrid(value); - }); + Object.entries(changes).forEach(([o, value]) => { + changes[o] = snapToGrid(value) + }) } - assignAttributes(selected, changes, 1000, true); - }; + assignAttributes(selected, changes, 1000, true) + } const box = getBBox(selected); - [ 'fill', 'stroke' ].forEach( (type) => { - const attrVal = selected.getAttribute(type); + ['fill', 'stroke'].forEach((type) => { + const attrVal = selected.getAttribute(type) if (attrVal && attrVal.startsWith('url(') && (m.a < 0 || m.d < 0)) { - const grad = getRefElem(attrVal); - const newgrad = grad.cloneNode(true); + const grad = getRefElem(attrVal) + const newgrad = grad.cloneNode(true) if (m.a < 0) { // flip x - const x1 = newgrad.getAttribute('x1'); - const x2 = newgrad.getAttribute('x2'); - newgrad.setAttribute('x1', -(x1 - 1)); - newgrad.setAttribute('x2', -(x2 - 1)); + 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 - const y1 = newgrad.getAttribute('y1'); - const y2 = newgrad.getAttribute('y2'); - newgrad.setAttribute('y1', -(y1 - 1)); - newgrad.setAttribute('y2', -(y2 - 1)); + const y1 = newgrad.getAttribute('y1') + const y2 = newgrad.getAttribute('y2') + newgrad.setAttribute('y1', -(y1 - 1)) + newgrad.setAttribute('y2', -(y2 - 1)) } - newgrad.id = svgCanvas.getDrawing().getNextId(); - findDefs().append(newgrad); - selected.setAttribute(type, 'url(#' + newgrad.id + ')'); + newgrad.id = svgCanvas.getDrawing().getNextId() + findDefs().append(newgrad) + selected.setAttribute(type, 'url(#' + newgrad.id + ')') } - }); + }) - const 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] - const existing = transformListToTransform(selected).matrix; - const tNew = matrixMultiply(existing.inverse(), m, existing); - changes.x = Number.parseFloat(changes.x) + tNew.e; - changes.y = Number.parseFloat(changes.y) + tNew.f; + const existing = transformListToTransform(selected).matrix + const 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 - const chlist = selected.transform.baseVal; - const mt = svgCanvas.getSvgRoot().createSVGTransform(); - mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m)); - chlist.clear(); - chlist.appendItem(mt); + const chlist = selected.transform.baseVal + const mt = svgCanvas.getSvgRoot().createSVGTransform() + mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m)) + chlist.clear() + chlist.appendItem(mt) } } // now we have a set of changes and an applied reduced transform list // we apply the changes directly to the DOM switch (elName) { - case 'foreignObject': - case 'rect': - case 'image': { + case 'foreignObject': + case 'rect': + case 'image': { // Allow images to be inverted (give them matrix when flipped) - if (elName === 'image' && (m.a < 0 || m.d < 0)) { + if (elName === 'image' && (m.a < 0 || m.d < 0)) { // Convert to matrix - const chlist = selected.transform.baseVal; - const mt = svgCanvas.getSvgRoot().createSVGTransform(); - mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m)); - chlist.clear(); - chlist.appendItem(mt); - } else { - 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); - changes.y = pt1.y + Math.min(0, changes.height); - changes.width = Math.abs(changes.width); - changes.height = Math.abs(changes.height); - } - finishUp(); - break; - } case 'ellipse': { - const c = remap(changes.cx, changes.cy); - changes.cx = c.x; - changes.cy = c.y; - changes.rx = scalew(changes.rx); - changes.ry = scaleh(changes.ry); - changes.rx = Math.abs(changes.rx); - changes.ry = Math.abs(changes.ry); - finishUp(); - break; - } case 'circle': { - 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 - const tbox = transformBox(box.x, box.y, box.width, box.height, m); - const w = tbox.tr.x - tbox.tl.x; const h = tbox.bl.y - tbox.tl.y; - changes.r = Math.min(w / 2, h / 2); - - if (changes.r) { changes.r = Math.abs(changes.r); } - finishUp(); - break; - } case 'line': { - 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; - } // Fallthrough - case 'text': - case 'tspan': - case 'use': { - finishUp(); - break; - } case 'g': { - const dataStorage = svgCanvas.getDataStorage(); - const gsvg = dataStorage.get(selected, 'gsvg'); - if (gsvg) { - assignAttributes(gsvg, changes, 1000, true); - } - break; - } case 'polyline': - case 'polygon': { - changes.points.forEach( (pt) => { - const { x, y } = remap(pt.x, pt.y); - pt.x = x; - pt.y = y; - }); - - // const len = changes.points.length; - let pstr = ''; - changes.points.forEach( (pt) => { - pstr += pt.x + ',' + pt.y + ' '; - }); - selected.setAttribute('points', pstr); - break; - } case 'path': { - const segList = selected.pathSegList; - let len = segList.numberOfItems; - changes.d = []; - for (let i = 0; i < len; ++i) { - const seg = segList.getItem(i); - changes.d[i] = { - type: seg.pathSegType, - x: seg.x, - y: seg.y, - x1: seg.x1, - y1: seg.y1, - x2: seg.x2, - y2: seg.y2, - r1: seg.r1, - r2: seg.r2, - angle: seg.angle, - largeArcFlag: seg.largeArcFlag, - sweepFlag: seg.sweepFlag - }; - } - - len = changes.d.length; - const firstseg = changes.d[0]; - let currentpt; - if (len > 0) { - currentpt = remap(firstseg.x, firstseg.y); - changes.d[0].x = currentpt.x; - changes.d[0].y = currentpt.y; - } - 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) { // absolute - const thisx = (seg.x !== undefined) ? seg.x : currentpt.x; // for V commands - const thisy = (seg.y !== undefined) ? seg.y : currentpt.y; // for H commands - 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); + const chlist = selected.transform.baseVal + const mt = svgCanvas.getSvgRoot().createSVGTransform() + mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m)) + chlist.clear() + chlist.appendItem(mt) + } else { + 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) + changes.y = pt1.y + Math.min(0, changes.height) + changes.width = Math.abs(changes.width) + changes.height = Math.abs(changes.height) } - } // for each segment + finishUp() + break + } case 'ellipse': { + const c = remap(changes.cx, changes.cy) + changes.cx = c.x + changes.cy = c.y + changes.rx = scalew(changes.rx) + changes.ry = scaleh(changes.ry) + changes.rx = Math.abs(changes.rx) + changes.ry = Math.abs(changes.ry) + finishUp() + break + } case 'circle': { + 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 + const tbox = transformBox(box.x, box.y, box.width, box.height, m) + const w = tbox.tr.x - tbox.tl.x; const h = tbox.bl.y - tbox.tl.y + changes.r = Math.min(w / 2, h / 2) - let dstr = ''; - changes.d.forEach( (seg) => { - const { type } = seg; - dstr += pathMap[type]; - switch (type) { - case 13: // relative horizontal line (h) - case 12: // absolute horizontal line (H) - dstr += seg.x + ' '; - break; - case 15: // relative vertical line (v) - case 14: // absolute vertical line (V) - dstr += seg.y + ' '; - break; - case 3: // relative move (m) - case 5: // relative line (l) - case 19: // relative smooth quad (t) - case 2: // absolute move (M) - case 4: // absolute line (L) - case 18: // absolute smooth quad (T) - dstr += seg.x + ',' + seg.y + ' '; - break; - case 7: // relative cubic (c) - case 6: // absolute cubic (C) - dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x2 + ',' + seg.y2 + ' ' + - seg.x + ',' + seg.y + ' '; - break; - case 9: // relative quad (q) - case 8: // absolute quad (Q) - dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x + ',' + seg.y + ' '; - break; - case 11: // relative elliptical arc (a) - case 10: // absolute elliptical arc (A) - dstr += seg.r1 + ',' + seg.r2 + ' ' + seg.angle + ' ' + Number(seg.largeArcFlag) + - ' ' + Number(seg.sweepFlag) + ' ' + seg.x + ',' + seg.y + ' '; - break; - case 17: // relative smooth cubic (s) - case 16: // absolute smooth cubic (S) - dstr += seg.x2 + ',' + seg.y2 + ' ' + seg.x + ',' + seg.y + ' '; - break; + if (changes.r) { changes.r = Math.abs(changes.r) } + finishUp() + break + } case 'line': { + 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 + } // Fallthrough + case 'text': + case 'tspan': + case 'use': { + finishUp() + break + } case 'g': { + const dataStorage = svgCanvas.getDataStorage() + const gsvg = dataStorage.get(selected, 'gsvg') + if (gsvg) { + assignAttributes(gsvg, changes, 1000, true) } - }); + break + } case 'polyline': + case 'polygon': { + changes.points.forEach((pt) => { + const { x, y } = remap(pt.x, pt.y) + pt.x = x + pt.y = y + }) - selected.setAttribute('d', dstr); - break; + // const len = changes.points.length; + let pstr = '' + changes.points.forEach((pt) => { + pstr += pt.x + ',' + pt.y + ' ' + }) + selected.setAttribute('points', pstr) + break + } case 'path': { + const segList = selected.pathSegList + let len = segList.numberOfItems + changes.d = [] + for (let i = 0; i < len; ++i) { + const seg = segList.getItem(i) + changes.d[i] = { + type: seg.pathSegType, + x: seg.x, + y: seg.y, + x1: seg.x1, + y1: seg.y1, + x2: seg.x2, + y2: seg.y2, + r1: seg.r1, + r2: seg.r2, + angle: seg.angle, + largeArcFlag: seg.largeArcFlag, + sweepFlag: seg.sweepFlag + } + } + + len = changes.d.length + const firstseg = changes.d[0] + let currentpt + if (len > 0) { + currentpt = remap(firstseg.x, firstseg.y) + changes.d[0].x = currentpt.x + changes.d[0].y = currentpt.y + } + 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) { // absolute + const thisx = (seg.x !== undefined) ? seg.x : currentpt.x // for V commands + const thisy = (seg.y !== undefined) ? seg.y : currentpt.y // for H commands + 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) + } + } // for each segment + + let dstr = '' + changes.d.forEach((seg) => { + const { type } = seg + dstr += pathMap[type] + switch (type) { + case 13: // relative horizontal line (h) + case 12: // absolute horizontal line (H) + dstr += seg.x + ' ' + break + case 15: // relative vertical line (v) + case 14: // absolute vertical line (V) + dstr += seg.y + ' ' + break + case 3: // relative move (m) + case 5: // relative line (l) + case 19: // relative smooth quad (t) + case 2: // absolute move (M) + case 4: // absolute line (L) + case 18: // absolute smooth quad (T) + dstr += seg.x + ',' + seg.y + ' ' + break + case 7: // relative cubic (c) + case 6: // absolute cubic (C) + dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x2 + ',' + seg.y2 + ' ' + + seg.x + ',' + seg.y + ' ' + break + case 9: // relative quad (q) + case 8: // absolute quad (Q) + dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x + ',' + seg.y + ' ' + break + case 11: // relative elliptical arc (a) + case 10: // absolute elliptical arc (A) + dstr += seg.r1 + ',' + seg.r2 + ' ' + seg.angle + ' ' + Number(seg.largeArcFlag) + + ' ' + Number(seg.sweepFlag) + ' ' + seg.x + ',' + seg.y + ' ' + break + case 17: // relative smooth cubic (s) + case 16: // absolute smooth cubic (S) + dstr += seg.x2 + ',' + seg.y2 + ' ' + seg.x + ',' + seg.y + ' ' + break + } + }) + + selected.setAttribute('d', dstr) + break + } } - } -}; +} diff --git a/src/svgcanvas/copy-elem.js b/src/svgcanvas/copy-elem.js index cc3f0d38..7fcc0e14 100644 --- a/src/svgcanvas/copy-elem.js +++ b/src/svgcanvas/copy-elem.js @@ -1,4 +1,4 @@ -import { preventClickDefault } from './utilities.js'; +import { preventClickDefault } from './utilities.js' /** * Create a clone of an element, updating its ID and its children's IDs when needed. @@ -9,37 +9,37 @@ import { preventClickDefault } from './utilities.js'; */ export const copyElem = function (el, getNextId) { // manually create a copy of the element - const newEl = document.createElementNS(el.namespaceURI, el.nodeName); + const newEl = document.createElementNS(el.namespaceURI, el.nodeName) Object.values(el.attributes).forEach((attr) => { - newEl.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value); - }); + newEl.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value) + }) // set the copied element's new id - newEl.removeAttribute('id'); - newEl.id = getNextId(); + newEl.removeAttribute('id') + newEl.id = getNextId() // now create copies of all children - el.childNodes.forEach(function(child){ + el.childNodes.forEach(function (child) { switch (child.nodeType) { - case 1: // element node - newEl.append(copyElem(child, getNextId)); - break; - case 3: // text node - newEl.textContent = child.nodeValue; - break; - default: - break; + case 1: // element node + newEl.append(copyElem(child, getNextId)) + break + case 3: // text node + newEl.textContent = child.nodeValue + break + default: + break } - }); + }) if (el.dataset.gsvg) { - newEl.dataset.gsvg = newEl.firstChild; + newEl.dataset.gsvg = newEl.firstChild } else if (el.dataset.symbol) { - const ref = el.dataset.symbol; - newEl.dataset.ref = ref; - newEl.dataset.symbol = ref; + const ref = el.dataset.symbol + newEl.dataset.ref = ref + newEl.dataset.symbol = ref } else if (newEl.tagName === 'image') { - preventClickDefault(newEl); + preventClickDefault(newEl) } - return newEl; -}; + return newEl +} diff --git a/src/svgcanvas/dataStorage.js b/src/svgcanvas/dataStorage.js index 50b0d194..26a4ade7 100644 --- a/src/svgcanvas/dataStorage.js +++ b/src/svgcanvas/dataStorage.js @@ -6,23 +6,23 @@ const dataStorage = { _storage: new WeakMap(), put: function (element, key, obj) { if (!this._storage.has(element)) { - this._storage.set(element, new Map()); + this._storage.set(element, new Map()) } - this._storage.get(element).set(key, obj); + this._storage.get(element).set(key, obj) }, get: function (element, key) { - return this._storage.get(element)?.get(key); + return this._storage.get(element)?.get(key) }, has: function (element, key) { - return this._storage.has(element) && this._storage.get(element).has(key); + return this._storage.has(element) && this._storage.get(element).has(key) }, remove: function (element, key) { - const ret = this._storage.get(element).delete(key); + const ret = this._storage.get(element).delete(key) if (!this._storage.get(element).size === 0) { - this._storage.delete(element); + this._storage.delete(element) } - return ret; + return ret } -}; +} -export default dataStorage; +export default dataStorage diff --git a/src/svgcanvas/draw.js b/src/svgcanvas/draw.js index 48770ef6..4e8ac203 100644 --- a/src/svgcanvas/draw.js +++ b/src/svgcanvas/draw.js @@ -5,28 +5,28 @@ * @copyright 2011 Jeff Schiller */ -import Layer from './layer.js'; -import HistoryRecordingService from './historyrecording.js'; +import Layer from './layer.js' +import HistoryRecordingService from './historyrecording.js' -import { NS } from './namespaces.js'; +import { NS } from './namespaces.js' import { toXml, getElem -} from './utilities.js'; +} from './utilities.js' import { copyElem as utilCopyElem -} from './copy-elem.js'; -import { getParentsUntil } from '../editor/components/jgraduate/Util.js'; +} from './copy-elem.js' +import { getParentsUntil } from '../editor/components/jgraduate/Util.js' -const visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'.split(','); +const visElems = '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 -}; -let randIds = RandomizeModes.LET_DOCUMENT_DECIDE; +} +let randIds = RandomizeModes.LET_DOCUMENT_DECIDE // Array with current disabled elements (for in-group editing) -let disabledElems = []; +let disabledElems = [] /** * Get a HistoryRecordingService. @@ -34,7 +34,7 @@ let disabledElems = []; * @returns {module:history.HistoryRecordingService} */ function historyRecordingService (hrService) { - return hrService || new HistoryRecordingService(svgCanvas.undoMgr); + return hrService || new HistoryRecordingService(svgCanvas.undoMgr) } /** @@ -43,8 +43,8 @@ function historyRecordingService (hrService) { * @returns {string} The layer name or empty string. */ function findLayerNameInGroup (group) { - const sel = group.querySelector('title'); - return sel ? sel.textContent : ''; + const sel = group.querySelector('title') + return sel ? sel.textContent : '' } /** @@ -53,10 +53,10 @@ function findLayerNameInGroup (group) { * @returns {string} - The new name. */ function getNewLayerName (existingLayerNames) { - let i = 1; + let i = 1 // TODO(codedread): What about internationalization of "Layer"? - while (existingLayerNames.includes(('Layer ' + i))) { i++; } - return 'Layer ' + i; + while (existingLayerNames.includes(('Layer ' + i))) { i++ } + return 'Layer ' + i } /** @@ -73,32 +73,32 @@ export class 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 element'); + throw new Error('Error: svgedit.draw.Drawing instance initialized without a element') } /** * The SVG DOM Element that represents this drawing. * @type {SVGSVGElement} */ - this.svgElem_ = svgElem; + this.svgElem_ = svgElem /** * The latest object number used in this drawing. * @type {Integer} */ - this.obj_num = 0; + this.obj_num = 0 /** * The prefix to prepend to each element id in the drawing. * @type {string} */ - this.idPrefix = optIdPrefix || 'svg_'; + this.idPrefix = optIdPrefix || 'svg_' /** * An array of released element ids to immediately reuse. * @type {Integer[]} */ - this.releasedNums = []; + this.releasedNums = [] /** * The z-ordered array of Layer objects. Each layer has a name @@ -106,7 +106,7 @@ export class Drawing { * The first layer is the one at the bottom of the rendering. * @type {Layer[]} */ - this.all_layers = []; + this.all_layers = [] /** * Map of all_layers by name. @@ -116,26 +116,26 @@ export class Drawing { * * @type {PlainObject} */ - this.layer_map = {}; + this.layer_map = {} /** * The current layer being used. * @type {Layer} */ - this.current_layer = null; + this.current_layer = null /** * The nonce to use to uniquely identify elements across drawings. * @type {!string} */ - this.nonce_ = ''; - const n = this.svgElem_.getAttributeNS(NS.SE, 'nonce'); + this.nonce_ = '' + 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) { - this.nonce_ = n; + this.nonce_ = n } else if (randIds === RandomizeModes.ALWAYS_RANDOMIZE) { - this.setNonce(Math.floor(Math.random() * 100001)); + this.setNonce(Math.floor(Math.random() * 100001)) } } @@ -146,24 +146,24 @@ export class Drawing { getElem_ (id) { if (this.svgElem_.querySelector) { // querySelector lookup - return this.svgElem_.querySelector('#' + id); + return this.svgElem_.querySelector('#' + id) } // jQuery lookup: twice as slow as xpath in FF - return this.svgElem_.querySelector('[id=' + id + ']'); + return this.svgElem_.querySelector('[id=' + id + ']') } /** * @returns {SVGSVGElement} */ getSvgElem () { - return this.svgElem_; + return this.svgElem_ } /** * @returns {!(string|Integer)} The previously set nonce */ getNonce () { - return this.nonce_; + return this.nonce_ } /** @@ -171,9 +171,9 @@ export class Drawing { * @returns {void} */ setNonce (n) { - this.svgElem_.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE); - this.svgElem_.setAttributeNS(NS.SE, 'se:nonce', n); - this.nonce_ = n; + this.svgElem_.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE) + this.svgElem_.setAttributeNS(NS.SE, 'se:nonce', n) + this.nonce_ = n } /** @@ -183,7 +183,7 @@ export class Drawing { clearNonce () { // We deliberately leave any se:nonce attributes alone, // we just don't use it to randomize ids. - this.nonce_ = ''; + this.nonce_ = '' } /** @@ -193,7 +193,7 @@ export class Drawing { getId () { return this.nonce_ ? this.idPrefix + this.nonce_ + '_' + this.obj_num - : this.idPrefix + this.obj_num; + : this.idPrefix + this.obj_num } /** @@ -201,35 +201,35 @@ export class Drawing { * @returns {string} The next object Id to use. */ getNextId () { - const oldObjNum = this.obj_num; - let restoreOldObjNum = false; + 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; + 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++; + this.obj_num++ } // Ensure the ID does not exist. - let id = this.getId(); + let id = this.getId() while (this.getElem_(id)) { if (restoreOldObjNum) { - this.obj_num = oldObjNum; - restoreOldObjNum = false; + this.obj_num = oldObjNum + restoreOldObjNum = false } - this.obj_num++; - id = this.getId(); + this.obj_num++ + id = this.getId() } // Restore the old object number if required. if (restoreOldObjNum) { - this.obj_num = oldObjNum; + this.obj_num = oldObjNum } - return id; + return id } /** @@ -241,23 +241,23 @@ export class Drawing { */ releaseId (id) { // confirm if this is a valid id for this Document, else return false - const front = this.idPrefix + (this.nonce_ ? this.nonce_ + '_' : ''); + const front = this.idPrefix + (this.nonce_ ? this.nonce_ + '_' : '') if (typeof id !== 'string' || !id.startsWith(front)) { - return false; + return false } // extract the obj_num of this id - const num = Number.parseInt(id.substr(front.length)); + 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; + return false } // push the released number into the released queue - this.releasedNums.push(num); + this.releasedNums.push(num) - return true; + return true } /** @@ -265,7 +265,7 @@ export class Drawing { * @returns {Integer} The number of layers in the current drawing. */ getNumLayers () { - return this.all_layers.length; + return this.all_layers.length } /** @@ -274,7 +274,7 @@ export class Drawing { * @returns {boolean} */ hasLayer (name) { - return this.layer_map[name] !== undefined; + return this.layer_map[name] !== undefined } /** @@ -283,14 +283,14 @@ export class Drawing { * @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() : ''; + 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; + return this.current_layer ? this.current_layer.getGroup() : null } /** @@ -299,8 +299,8 @@ export class Drawing { * @returns {SVGGElement} The SVGGElement representing the named layer or null. */ getLayerByName (name) { - const layer = this.layer_map[name]; - return layer ? layer.getGroup() : null; + const layer = this.layer_map[name] + return layer ? layer.getGroup() : null } /** @@ -309,7 +309,7 @@ export class Drawing { * @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() : ''; + return this.current_layer ? this.current_layer.getName() : '' } /** @@ -319,16 +319,16 @@ export class Drawing { * @returns {string|null} The new name if changed; otherwise, null. */ setCurrentLayerName (name, hrService) { - let finalName = null; + let finalName = null if (this.current_layer) { - const oldName = this.current_layer.getName(); - finalName = this.current_layer.setName(name, hrService); + 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; + delete this.layer_map[oldName] + this.layer_map[finalName] = this.current_layer } } - return finalName; + return finalName } /** @@ -337,43 +337,43 @@ export class Drawing { * @returns {{title: SVGGElement, previousName: string}|null} If the name was changed, returns {title:SVGGElement, previousName:string}; otherwise null. */ setCurrentLayerPosition (newpos) { - const layerCount = this.getNumLayers(); + const layerCount = this.getNumLayers() if (!this.current_layer || newpos < 0 || newpos >= layerCount) { - return null; + return null } - let oldpos; + let oldpos for (oldpos = 0; oldpos < layerCount; ++oldpos) { - if (this.all_layers[oldpos] === this.current_layer) { break; } + 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 === 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; + const currentGroup = this.current_layer.getGroup() + const oldNextSibling = currentGroup.nextSibling - let refGroup = null; + let refGroup = null if (newpos > oldpos) { if (newpos < layerCount - 1) { - refGroup = this.all_layers[newpos + 1].getGroup(); + 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(); + refGroup = this.all_layers[newpos].getGroup() } - this.svgElem_.insertBefore(currentGroup, refGroup); // Ok to replace with `refGroup.before(currentGroup);`? + this.svgElem_.insertBefore(currentGroup, refGroup) // Ok to replace with `refGroup.before(currentGroup);`? - this.identifyLayers(); - this.setCurrentLayer(this.getLayerName(newpos)); + this.identifyLayers() + this.setCurrentLayer(this.getLayerName(newpos)) return { currentGroup, oldNextSibling - }; + } } - return null; + return null } /** @@ -381,39 +381,39 @@ export class Drawing { * @returns {void} */ mergeLayer (hrService) { - const currentGroup = this.current_layer.getGroup(); - const prevGroup = currentGroup.previousElementSibling; - if (!prevGroup) { return; } + const currentGroup = this.current_layer.getGroup() + const prevGroup = currentGroup.previousElementSibling + if (!prevGroup) { return } - hrService.startBatchCommand('Merge Layer'); + hrService.startBatchCommand('Merge Layer') - const layerNextSibling = currentGroup.nextSibling; - hrService.removeElement(currentGroup, layerNextSibling, this.svgElem_); + const layerNextSibling = currentGroup.nextSibling + hrService.removeElement(currentGroup, layerNextSibling, this.svgElem_) while (currentGroup.firstChild) { - const child = currentGroup.firstChild; + const child = currentGroup.firstChild if (child.localName === 'title') { - hrService.removeElement(child, child.nextSibling, currentGroup); - child.remove(); - continue; + hrService.removeElement(child, child.nextSibling, currentGroup) + child.remove() + continue } - const oldNextSibling = child.nextSibling; - prevGroup.append(child); - hrService.moveElement(child, oldNextSibling, currentGroup); + const oldNextSibling = child.nextSibling + prevGroup.append(child) + hrService.moveElement(child, oldNextSibling, currentGroup) } // Remove current layer's group - this.current_layer.removeGroup(); + 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); + 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]; + 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(); + hrService.endBatchCommand() } /** @@ -422,13 +422,13 @@ export class Drawing { */ mergeAllLayers (hrService) { // Set the current layer to the last layer. - this.current_layer = this.all_layers[this.all_layers.length - 1]; + this.current_layer = this.all_layers[this.all_layers.length - 1] - hrService.startBatchCommand('Merge all Layers'); + hrService.startBatchCommand('Merge all Layers') while (this.all_layers.length > 1) { - this.mergeLayer(hrService); + this.mergeLayer(hrService) } - hrService.endBatchCommand(); + hrService.endBatchCommand() } /** @@ -439,16 +439,16 @@ export class Drawing { * @returns {boolean} `true` if the current layer was switched, otherwise `false` */ setCurrentLayer (name) { - const layer = this.layer_map[name]; + const layer = this.layer_map[name] if (layer) { if (this.current_layer) { - this.current_layer.deactivate(); + this.current_layer.deactivate() } - this.current_layer = layer; - this.current_layer.activate(); - return true; + this.current_layer = layer + this.current_layer.activate() + return true } - return false; + return false } /** @@ -459,11 +459,11 @@ export class Drawing { */ deleteCurrentLayer () { if (this.current_layer && this.getNumLayers() > 1) { - const oldLayerGroup = this.current_layer.removeGroup(); - this.identifyLayers(); - return oldLayerGroup; + const oldLayerGroup = this.current_layer.removeGroup() + this.identifyLayers() + return oldLayerGroup } - return null; + return null } /** @@ -472,46 +472,46 @@ export class Drawing { * @returns {void} */ identifyLayers () { - this.all_layers = []; - this.layer_map = {}; - const numchildren = this.svgElem_.childNodes.length; + this.all_layers = [] + this.layer_map = {} + const numchildren = this.svgElem_.childNodes.length // loop through all children of SVG element - const orphans = []; const layernames = []; - let layer = null; - let childgroups = false; + const orphans = []; const layernames = [] + let layer = null + let childgroups = false for (let i = 0; i < numchildren; ++i) { - const child = this.svgElem_.childNodes.item(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); + 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; + 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); + orphans.push(child) } } else if (visElems.includes(child.nodeName)) { // Child is "visible" (i.e. not a or element), so it is an orphan - orphans.push(child); + 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; + layer = new Layer(getNewLayerName(layernames), null, this.svgElem_) + layer.appendChildren(orphans) + this.all_layers.push(layer) + this.layer_map[name] = layer } else { - layer.activate(); + layer.activate() } - this.current_layer = layer; + this.current_layer = layer } /** @@ -524,26 +524,26 @@ export class Drawing { */ createLayer (name, hrService) { if (this.current_layer) { - this.current_layer.deactivate(); + 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)); + name = getNewLayerName(Object.keys(this.layer_map)) } // Crate new layer and add to DOM as last layer - const layer = new Layer(name, null, this.svgElem_); + 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(); + hrService.startBatchCommand('Create Layer') + hrService.insertElement(layer.getGroup()) + hrService.endBatchCommand() } - this.all_layers.push(layer); - this.layer_map[name] = layer; - this.current_layer = layer; - return layer.getGroup(); + this.all_layers.push(layer) + this.layer_map[name] = layer + this.current_layer = layer + return layer.getGroup() } /** @@ -554,41 +554,41 @@ export class Drawing { * also the current layer of this drawing. */ cloneLayer (name, hrService) { - if (!this.current_layer) { return null; } - this.current_layer.deactivate(); + 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)); + name = getNewLayerName(Object.keys(this.layer_map)) } // Create new group and add to DOM just after current_layer - const currentGroup = this.current_layer.getGroup(); - const layer = new Layer(name, currentGroup, this.svgElem_); - const group = layer.getGroup(); + const currentGroup = this.current_layer.getGroup() + const layer = new Layer(name, currentGroup, this.svgElem_) + const group = layer.getGroup() // Clone children - const children = [ ...currentGroup.childNodes ]; + const children = [...currentGroup.childNodes] children.forEach((child) => { - if (child.localName === 'title') { return; } - group.append(this.copyElem(child)); - }); + if (child.localName === 'title') { return } + group.append(this.copyElem(child)) + }) if (hrService) { - hrService.startBatchCommand('Duplicate Layer'); - hrService.insertElement(group); - hrService.endBatchCommand(); + hrService.startBatchCommand('Duplicate Layer') + hrService.insertElement(group) + hrService.endBatchCommand() } // Update layer containers and current_layer. - const index = this.all_layers.indexOf(this.current_layer); + const index = this.all_layers.indexOf(this.current_layer) if (index >= 0) { - this.all_layers.splice(index + 1, 0, layer); + this.all_layers.splice(index + 1, 0, layer) } else { - this.all_layers.push(layer); + this.all_layers.push(layer) } - this.layer_map[name] = layer; - this.current_layer = layer; - return group; + this.layer_map[name] = layer + this.current_layer = layer + return group } /** @@ -598,8 +598,8 @@ export class Drawing { * @returns {boolean} The visibility state of the layer, or `false` if the layer name was invalid. */ getLayerVisibility (layerName) { - const layer = this.layer_map[layerName]; - return layer ? layer.isVisible() : false; + const layer = this.layer_map[layerName] + return layer ? layer.isVisible() : false } /** @@ -613,12 +613,12 @@ export class Drawing { */ setLayerVisibility (layerName, bVisible) { if (typeof bVisible !== 'boolean') { - return null; + return null } - const layer = this.layer_map[layerName]; - if (!layer) { return null; } - layer.setVisible(bVisible); - return layer.getGroup(); + const layer = this.layer_map[layerName] + if (!layer) { return null } + layer.setVisible(bVisible) + return layer.getGroup() } /** @@ -628,9 +628,9 @@ export class Drawing { * if `layerName` is not a valid layer */ getLayerOpacity (layerName) { - const layer = this.layer_map[layerName]; - if (!layer) { return null; } - return layer.getOpacity(); + const layer = this.layer_map[layerName] + if (!layer) { return null } + return layer.getOpacity() } /** @@ -647,11 +647,11 @@ export class Drawing { */ setLayerOpacity (layerName, opacity) { if (typeof opacity !== 'number' || opacity < 0.0 || opacity > 1.0) { - return; + return } - const layer = this.layer_map[layerName]; + const layer = this.layer_map[layerName] if (layer) { - layer.setOpacity(opacity); + layer.setOpacity(opacity) } } @@ -661,9 +661,9 @@ export class Drawing { * @returns {Element} */ copyElem (el) { - const that = this; - const getNextIdClosure = function () { return that.getNextId(); }; - return utilCopyElem(el, getNextIdClosure); + const that = this + const getNextIdClosure = function () { return that.getNextId() } + return utilCopyElem(el, getNextIdClosure) } } @@ -678,14 +678,14 @@ export class Drawing { export const randomizeIds = function (enableRandomization, currentDrawing) { randIds = enableRandomization === false ? RandomizeModes.NEVER_RANDOMIZE - : RandomizeModes.ALWAYS_RANDOMIZE; + : RandomizeModes.ALWAYS_RANDOMIZE if (randIds === RandomizeModes.ALWAYS_RANDOMIZE && !currentDrawing.getNonce()) { - currentDrawing.setNonce(Math.floor(Math.random() * 100001)); + currentDrawing.setNonce(Math.floor(Math.random() * 100001)) } else if (randIds === RandomizeModes.NEVER_RANDOMIZE && currentDrawing.getNonce()) { - currentDrawing.clearNonce(); + currentDrawing.clearNonce() } -}; +} // Layer API Functions @@ -748,15 +748,15 @@ export const randomizeIds = function (enableRandomization, currentDrawing) { * @returns {void} */ -let svgCanvas; +let svgCanvas /** * @function module:draw.init * @param {module:draw.DrawCanvasInit} canvas * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; -}; + svgCanvas = canvas +} /** * Updates layer system. @@ -764,9 +764,9 @@ export const init = function (canvas) { * @returns {void} */ export const identifyLayers = function () { - leaveContext(); - svgCanvas.getCurrentDrawing().identifyLayers(); -}; + leaveContext() + svgCanvas.getCurrentDrawing().identifyLayers() +} /** * Creates a new top-level layer in the drawing with the given name, sets the current layer @@ -782,10 +782,10 @@ export const createLayer = function (name, hrService) { const newLayer = svgCanvas.getCurrentDrawing().createLayer( name, historyRecordingService(hrService) - ); - svgCanvas.clearSelection(); - svgCanvas.call('changed', [ newLayer ]); -}; + ) + svgCanvas.clearSelection() + svgCanvas.call('changed', [newLayer]) +} /** * Creates a new top-level layer in the drawing with the given name, copies all the current layer's contents @@ -799,12 +799,12 @@ export const createLayer = function (name, hrService) { */ export const cloneLayer = function (name, hrService) { // Clone the current layer and make the cloned layer the new current layer - const newLayer = svgCanvas.getCurrentDrawing().cloneLayer(name, historyRecordingService(hrService)); + const newLayer = svgCanvas.getCurrentDrawing().cloneLayer(name, historyRecordingService(hrService)) - svgCanvas.clearSelection(); - leaveContext(); - svgCanvas.call('changed', [ newLayer ]); -}; + svgCanvas.clearSelection() + leaveContext() + svgCanvas.call('changed', [newLayer]) +} /** * Deletes the current layer from the drawing and then clears the selection. This function @@ -814,22 +814,22 @@ export const cloneLayer = function (name, hrService) { * @returns {boolean} `true` if an old layer group was found to delete */ export const deleteCurrentLayer = function () { - const { BatchCommand, RemoveElementCommand } = svgCanvas.history; - let currentLayer = svgCanvas.getCurrentDrawing().getCurrentLayer(); - const { nextSibling } = currentLayer; - const parent = currentLayer.parentNode; - currentLayer = svgCanvas.getCurrentDrawing().deleteCurrentLayer(); + const { BatchCommand, RemoveElementCommand } = svgCanvas.history + let currentLayer = svgCanvas.getCurrentDrawing().getCurrentLayer() + const { nextSibling } = currentLayer + const parent = currentLayer.parentNode + currentLayer = svgCanvas.getCurrentDrawing().deleteCurrentLayer() if (currentLayer) { - const batchCmd = new BatchCommand('Delete Layer'); + const batchCmd = new BatchCommand('Delete Layer') // store in our Undo History - batchCmd.addSubCommand(new RemoveElementCommand(currentLayer, nextSibling, parent)); - svgCanvas.addCommandToHistory(batchCmd); - svgCanvas.clearSelection(); - svgCanvas.call('changed', [ parent ]); - return true; + batchCmd.addSubCommand(new RemoveElementCommand(currentLayer, nextSibling, parent)) + svgCanvas.addCommandToHistory(batchCmd) + svgCanvas.clearSelection() + svgCanvas.call('changed', [parent]) + return true } - return false; -}; + return false +} /** * Sets the current layer. If the name is not a valid layer name, then this function returns @@ -839,12 +839,12 @@ export const deleteCurrentLayer = function () { * @returns {boolean} true if the current layer was switched, otherwise false */ export const setCurrentLayer = function (name) { - const result = svgCanvas.getCurrentDrawing().setCurrentLayer(toXml(name)); + const result = svgCanvas.getCurrentDrawing().setCurrentLayer(toXml(name)) if (result) { - svgCanvas.clearSelection(); + svgCanvas.clearSelection() } - return result; -}; + return result +} /** * Renames the current layer. If the layer name is not valid (i.e. unique), then this function @@ -856,17 +856,17 @@ export const setCurrentLayer = function (name) { * @returns {boolean} Whether the rename succeeded */ export const renameCurrentLayer = function (newName) { - const drawing = svgCanvas.getCurrentDrawing(); - const layer = drawing.getCurrentLayer(); + const drawing = svgCanvas.getCurrentDrawing() + const layer = drawing.getCurrentLayer() if (layer) { - const result = drawing.setCurrentLayerName(newName, historyRecordingService()); + const result = drawing.setCurrentLayerName(newName, historyRecordingService()) if (result) { - svgCanvas.call('changed', [ layer ]); - return true; + svgCanvas.call('changed', [layer]) + return true } } - return false; -}; + return false +} /** * Changes the position of the current layer to the new value. If the new index is not valid, @@ -878,15 +878,15 @@ export const renameCurrentLayer = function (newName) { * @returns {boolean} `true` if the current layer position was changed, `false` otherwise. */ export const setCurrentLayerPosition = function (newPos) { - const { MoveElementCommand } = svgCanvas.history; - const drawing = svgCanvas.getCurrentDrawing(); - const result = drawing.setCurrentLayerPosition(newPos); + const { MoveElementCommand } = svgCanvas.history + const drawing = svgCanvas.getCurrentDrawing() + const result = drawing.setCurrentLayerPosition(newPos) if (result) { - svgCanvas.addCommandToHistory(new MoveElementCommand(result.currentGroup, result.oldNextSibling, svgCanvas.getSvgContent())); - return true; + svgCanvas.addCommandToHistory(new MoveElementCommand(result.currentGroup, result.oldNextSibling, svgCanvas.getSvgContent())) + return true } - return false; -}; + return false +} /** * Sets the visibility of the layer. If the layer name is not valid, this function return @@ -897,24 +897,24 @@ export const setCurrentLayerPosition = function (newPos) { * @returns {boolean} true if the layer's visibility was set, false otherwise */ export const setLayerVisibility = function (layerName, bVisible) { - const { ChangeElementCommand } = svgCanvas.history; - const drawing = svgCanvas.getCurrentDrawing(); - const prevVisibility = drawing.getLayerVisibility(layerName); - const layer = drawing.setLayerVisibility(layerName, bVisible); + const { ChangeElementCommand } = svgCanvas.history + const drawing = svgCanvas.getCurrentDrawing() + const prevVisibility = drawing.getLayerVisibility(layerName) + const layer = drawing.setLayerVisibility(layerName, bVisible) if (layer) { - const oldDisplay = prevVisibility ? 'inline' : 'none'; - svgCanvas.addCommandToHistory(new ChangeElementCommand(layer, { display: oldDisplay }, 'Layer Visibility')); + const oldDisplay = prevVisibility ? 'inline' : 'none' + svgCanvas.addCommandToHistory(new ChangeElementCommand(layer, { display: oldDisplay }, 'Layer Visibility')) } else { - return false; + return false } if (layer === drawing.getCurrentLayer()) { - svgCanvas.clearSelection(); - svgCanvas.pathActions.clear(); + svgCanvas.clearSelection() + svgCanvas.pathActions.clear() } // call('changed', [selected]); - return true; -}; + return true +} /** * Moves the selected elements to layerName. If the name is not a valid layer name, then `false` @@ -924,31 +924,31 @@ export const setLayerVisibility = function (layerName, bVisible) { * @returns {boolean} Whether the selected elements were moved to the layer. */ export const moveSelectedToLayer = function (layerName) { - const { BatchCommand, MoveElementCommand } = svgCanvas.history; + const { BatchCommand, MoveElementCommand } = svgCanvas.history // find the layer - const drawing = svgCanvas.getCurrentDrawing(); - const layer = drawing.getLayerByName(layerName); - if (!layer) { return false; } + const drawing = svgCanvas.getCurrentDrawing() + const layer = drawing.getLayerByName(layerName) + if (!layer) { return false } - const batchCmd = new BatchCommand('Move Elements to Layer'); + const batchCmd = new BatchCommand('Move Elements to Layer') // loop for each selected element and move it - const selElems = svgCanvas.getSelectedElements(); - let i = selElems.length; + const selElems = svgCanvas.getSelectedElements() + let i = selElems.length while (i--) { - const elem = selElems[i]; - if (!elem) { continue; } - const oldNextSibling = elem.nextSibling; + const elem = selElems[i] + if (!elem) { continue } + const oldNextSibling = elem.nextSibling // TODO: this is pretty brittle! - const oldLayer = elem.parentNode; - layer.append(elem); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldLayer)); + const oldLayer = elem.parentNode + layer.append(elem) + batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldLayer)) } - svgCanvas.addCommandToHistory(batchCmd); + svgCanvas.addCommandToHistory(batchCmd) - return true; -}; + return true +} /** * @function module:draw.mergeLayer @@ -956,11 +956,11 @@ export const moveSelectedToLayer = function (layerName) { * @returns {void} */ export const mergeLayer = function (hrService) { - svgCanvas.getCurrentDrawing().mergeLayer(historyRecordingService(hrService)); - svgCanvas.clearSelection(); - leaveContext(); - svgCanvas.changeSvgContent(); -}; + svgCanvas.getCurrentDrawing().mergeLayer(historyRecordingService(hrService)) + svgCanvas.clearSelection() + leaveContext() + svgCanvas.changeSvgContent() +} /** * @function module:draw.mergeAllLayers @@ -968,11 +968,11 @@ export const mergeLayer = function (hrService) { * @returns {void} */ export const mergeAllLayers = function (hrService) { - svgCanvas.getCurrentDrawing().mergeAllLayers(historyRecordingService(hrService)); - svgCanvas.clearSelection(); - leaveContext(); - svgCanvas.changeSvgContent(); -}; + svgCanvas.getCurrentDrawing().mergeAllLayers(historyRecordingService(hrService)) + svgCanvas.clearSelection() + leaveContext() + svgCanvas.changeSvgContent() +} /** * Return from a group context to the regular kind, make any previously @@ -982,25 +982,25 @@ export const mergeAllLayers = function (hrService) { * @returns {void} */ export const leaveContext = function () { - const len = disabledElems.length; - const dataStorage = svgCanvas.getDataStorage(); + const len = disabledElems.length + const dataStorage = svgCanvas.getDataStorage() if (len) { for (let i = 0; i < len; i++) { - const elem = disabledElems[i]; - const orig = dataStorage.get(elem, 'orig_opac'); + const elem = disabledElems[i] + const orig = dataStorage.get(elem, 'orig_opac') if (orig !== 1) { - elem.setAttribute('opacity', orig); + elem.setAttribute('opacity', orig) } else { - elem.removeAttribute('opacity'); + elem.removeAttribute('opacity') } - elem.setAttribute('style', 'pointer-events: inherit'); + elem.setAttribute('style', 'pointer-events: inherit') } - disabledElems = []; - svgCanvas.clearSelection(true); - svgCanvas.call('contextset', null); + disabledElems = [] + svgCanvas.clearSelection(true) + svgCanvas.call('contextset', null) } - svgCanvas.setCurrentGroup(null); -}; + svgCanvas.setCurrentGroup(null) +} /** * Set the current context (for in-group editing). @@ -1010,42 +1010,42 @@ export const leaveContext = function () { * @returns {void} */ export const setContext = function (elem) { - const dataStorage = svgCanvas.getDataStorage(); - leaveContext(); + const dataStorage = svgCanvas.getDataStorage() + leaveContext() if (typeof elem === 'string') { - elem = getElem(elem); + elem = getElem(elem) } // Edit inside this group - svgCanvas.setCurrentGroup(elem); + svgCanvas.setCurrentGroup(elem) // Disable other elements - const parentsUntil = getParentsUntil(elem, '#svgcontent'); - const siblings = []; + const parentsUntil = getParentsUntil(elem, '#svgcontent') + const siblings = [] parentsUntil.forEach(function (parent) { - const elements = Array.prototype.filter.call(parent.parentNode.children, function(child){ - return child !== parent; - }); + const elements = Array.prototype.filter.call(parent.parentNode.children, function (child) { + return child !== parent + }) elements.forEach(function (element) { - siblings.push(element); - }); - }); + siblings.push(element) + }) + }) siblings.forEach(function (curthis) { - const opac = curthis.getAttribute('opacity') || 1; + const opac = curthis.getAttribute('opacity') || 1 // Store the original's opacity - dataStorage.put(curthis, 'orig_opac', opac); - curthis.setAttribute('opacity', opac * 0.33); - curthis.setAttribute('style', 'pointer-events: none'); - disabledElems.push(curthis); - }); - svgCanvas.clearSelection(); - svgCanvas.call('contextset', svgCanvas.getCurrentGroup()); -}; + dataStorage.put(curthis, 'orig_opac', opac) + curthis.setAttribute('opacity', opac * 0.33) + curthis.setAttribute('style', 'pointer-events: none') + disabledElems.push(curthis) + }) + svgCanvas.clearSelection() + svgCanvas.call('contextset', svgCanvas.getCurrentGroup()) +} /** * @memberof module:draw * @class Layer * @see {@link module:layer.Layer} */ -export { Layer }; +export { Layer } diff --git a/src/svgcanvas/elem-get-set.js b/src/svgcanvas/elem-get-set.js index 8dbca9e0..54fed45f 100644 --- a/src/svgcanvas/elem-get-set.js +++ b/src/svgcanvas/elem-get-set.js @@ -4,18 +4,18 @@ * @copyright 2011 Jeff Schiller */ -import { jGraduate } from '../editor/components/jgraduate/jQuery.jGraduate.js'; -import { NS } from './namespaces.js'; +import { jGraduate } from '../editor/components/jgraduate/jQuery.jGraduate.js' +import { NS } from './namespaces.js' import { getVisibleElements, getStrokedBBoxDefaultVisible, findDefs, walkTree, isNullish, getHref, setHref, getElem -} from './utilities.js'; +} from './utilities.js' import { convertToNum -} from '../common/units.js'; -import { getParents } from '../editor/components/jgraduate/Util.js'; +} from '../common/units.js' +import { getParents } from '../editor/components/jgraduate/Util.js' -let svgCanvas = null; +let svgCanvas = null /** * @function module:elem-get-set.init @@ -23,24 +23,24 @@ let svgCanvas = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; -}; + svgCanvas = canvas +} /** * @function module:elem-get-set.SvgCanvas#getResolution * @returns {DimensionsAndZoom} The current dimensions and zoom level in an object */ export const getResolutionMethod = function () { - const zoom = svgCanvas.getZoom(); - const w = svgCanvas.getSvgContent().getAttribute('width') / zoom; - const h = svgCanvas.getSvgContent().getAttribute('height') / zoom; + const zoom = svgCanvas.getZoom() + const w = svgCanvas.getSvgContent().getAttribute('width') / zoom + const h = svgCanvas.getSvgContent().getAttribute('height') / zoom return { w, h, zoom - }; -}; + } +} /** * @function module:elem-get-set.SvgCanvas#getTitle @@ -49,23 +49,23 @@ export const getResolutionMethod = function () { * `undefined` if no element is passed nd there are no selected elements. */ export const getTitleMethod = function (elem) { - const selectedElements = svgCanvas.getSelectedElements(); - const dataStorage = svgCanvas.getDataStorage(); - elem = elem || selectedElements[0]; - if (!elem) { return undefined; } + const selectedElements = svgCanvas.getSelectedElements() + const dataStorage = svgCanvas.getDataStorage() + elem = elem || selectedElements[0] + if (!elem) { return undefined } if (dataStorage.has(elem, 'gsvg')) { - elem = dataStorage.get(elem, 'gsvg'); + elem = dataStorage.get(elem, 'gsvg') } else if (dataStorage.has(elem, 'symbol')) { - elem = dataStorage.get(elem, 'symbol'); + elem = dataStorage.get(elem, 'symbol') } - const childs = elem.childNodes; + const childs = elem.childNodes for (const child of childs) { if (child.nodeName === 'title') { - return child.textContent; + return child.textContent } } - return ''; -}; + return '' +} /** * Sets the group/SVG's title content. @@ -78,39 +78,39 @@ export const setGroupTitleMethod = function (val) { const { InsertElementCommand, RemoveElementCommand, ChangeElementCommand, BatchCommand - } = svgCanvas.history; - const selectedElements = svgCanvas.getSelectedElements(); - const dataStorage = svgCanvas.getDataStorage(); - let elem = selectedElements[0]; + } = svgCanvas.history + const selectedElements = svgCanvas.getSelectedElements() + const dataStorage = svgCanvas.getDataStorage() + let elem = selectedElements[0] if (dataStorage.has(elem, 'gsvg')) { - elem = dataStorage.get(elem, 'gsvg'); + elem = dataStorage.get(elem, 'gsvg') } - const ts = elem.querySelectorAll('title'); + const ts = elem.querySelectorAll('title') - const batchCmd = new BatchCommand('Set Label'); + const batchCmd = new BatchCommand('Set Label') - let title; + let title if (!val.length) { // Remove title element - const tsNextSibling = ts.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(ts[0], tsNextSibling, elem)); - ts.remove(); + const tsNextSibling = ts.nextSibling + batchCmd.addSubCommand(new RemoveElementCommand(ts[0], tsNextSibling, elem)) + ts.remove() } else if (ts.length) { // Change title contents - title = ts[0]; - batchCmd.addSubCommand(new ChangeElementCommand(title, { '#text': title.textContent })); - title.textContent = val; + title = ts[0] + batchCmd.addSubCommand(new ChangeElementCommand(title, { '#text': title.textContent })) + title.textContent = val } else { // Add title element - title = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'title'); - title.textContent = val; - elem.insertBefore(title, elem.firstChild); - batchCmd.addSubCommand(new InsertElementCommand(title)); + title = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'title') + title.textContent = val + elem.insertBefore(title, elem.firstChild) + batchCmd.addSubCommand(new InsertElementCommand(title)) } - svgCanvas.addCommandToHistory(batchCmd); -}; + svgCanvas.addCommandToHistory(batchCmd) +} /** * Adds/updates a title element for the document with the given name. @@ -120,34 +120,34 @@ export const setGroupTitleMethod = function (val) { * @returns {void} */ export const setDocumentTitleMethod = function (newTitle) { - const { ChangeElementCommand, BatchCommand } = svgCanvas.history; - const childs = svgCanvas.getSvgContent().childNodes; - let docTitle = false; let oldTitle = ''; + const { ChangeElementCommand, BatchCommand } = svgCanvas.history + const childs = svgCanvas.getSvgContent().childNodes + let docTitle = false; let oldTitle = '' - const batchCmd = new BatchCommand('Change Image Title'); + const batchCmd = new BatchCommand('Change Image Title') for (const child of childs) { if (child.nodeName === 'title') { - docTitle = child; - oldTitle = docTitle.textContent; - break; + docTitle = child + oldTitle = docTitle.textContent + break } } if (!docTitle) { - docTitle = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'title'); - svgCanvas.getSvgContent().insertBefore(docTitle, svgCanvas.getSvgContent().firstChild); + docTitle = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'title') + svgCanvas.getSvgContent().insertBefore(docTitle, svgCanvas.getSvgContent().firstChild) // svgContent.firstChild.before(docTitle); // Ok to replace above with this? } if (newTitle.length) { - docTitle.textContent = newTitle; + docTitle.textContent = newTitle } else { // No title given, so element is not necessary - docTitle.remove(); + docTitle.remove() } - batchCmd.addSubCommand(new ChangeElementCommand(docTitle, { '#text': oldTitle })); - svgCanvas.addCommandToHistory(batchCmd); -}; + batchCmd.addSubCommand(new ChangeElementCommand(docTitle, { '#text': oldTitle })) + svgCanvas.addCommandToHistory(batchCmd) +} /** * Changes the document's dimensions to the given size. @@ -160,59 +160,59 @@ export const setDocumentTitleMethod = function (newTitle) { * It will fail on "fit to content" option with no content to fit to. */ export const setResolutionMethod = function (x, y) { - const { ChangeElementCommand, BatchCommand } = svgCanvas.history; - const zoom = svgCanvas.getZoom(); - const res = svgCanvas.getResolution(); - const { w, h } = res; - let batchCmd; + const { ChangeElementCommand, BatchCommand } = svgCanvas.history + const zoom = svgCanvas.getZoom() + const res = svgCanvas.getResolution() + const { w, h } = res + let batchCmd if (x === 'fit') { // Get bounding box - const bbox = getStrokedBBoxDefaultVisible(); + const bbox = getStrokedBBoxDefaultVisible() if (bbox) { - batchCmd = new BatchCommand('Fit Canvas to Content'); - const visEls = getVisibleElements(); - svgCanvas.addToSelection(visEls); - const dx = []; const dy = []; - visEls.forEach(function(_item, _i){ - dx.push(bbox.x * -1); - dy.push(bbox.y * -1); - }); + batchCmd = new BatchCommand('Fit Canvas to Content') + const visEls = getVisibleElements() + svgCanvas.addToSelection(visEls) + const dx = []; const dy = [] + visEls.forEach(function (_item, _i) { + dx.push(bbox.x * -1) + dy.push(bbox.y * -1) + }) - const cmd = svgCanvas.moveSelectedElements(dx, dy, true); - batchCmd.addSubCommand(cmd); - svgCanvas.clearSelection(); + const cmd = svgCanvas.moveSelectedElements(dx, dy, true) + batchCmd.addSubCommand(cmd) + svgCanvas.clearSelection() - x = Math.round(bbox.width); - y = Math.round(bbox.height); + x = Math.round(bbox.width) + y = Math.round(bbox.height) } else { - return false; + return false } } if (x !== w || y !== h) { if (!batchCmd) { - batchCmd = new BatchCommand('Change Image Dimensions'); + batchCmd = new BatchCommand('Change Image Dimensions') } - x = convertToNum('width', x); - y = convertToNum('height', y); + x = convertToNum('width', x) + y = convertToNum('height', y) - svgCanvas.getSvgContent().setAttribute('width', x); - svgCanvas.getSvgContent().setAttribute('height', y); + svgCanvas.getSvgContent().setAttribute('width', x) + svgCanvas.getSvgContent().setAttribute('height', y) - this.contentW = x; - this.contentH = y; - batchCmd.addSubCommand(new ChangeElementCommand(svgCanvas.getSvgContent(), { width: w, height: h })); + this.contentW = x + this.contentH = y + batchCmd.addSubCommand(new ChangeElementCommand(svgCanvas.getSvgContent(), { width: w, height: h })) - svgCanvas.getSvgContent().setAttribute('viewBox', [ 0, 0, x / zoom, y / zoom ].join(' ')); - batchCmd.addSubCommand(new ChangeElementCommand(svgCanvas.getSvgContent(), { viewBox: [ '0 0', w, h ].join(' ') })); + svgCanvas.getSvgContent().setAttribute('viewBox', [0, 0, x / zoom, y / zoom].join(' ')) + batchCmd.addSubCommand(new ChangeElementCommand(svgCanvas.getSvgContent(), { viewBox: ['0 0', w, h].join(' ') })) - svgCanvas.addCommandToHistory(batchCmd); - svgCanvas.call('changed', [ svgCanvas.getSvgContent() ]); + svgCanvas.addCommandToHistory(batchCmd) + svgCanvas.call('changed', [svgCanvas.getSvgContent()]) } - return true; -}; + return true +} /** * Returns the editor's namespace URL, optionally adding it to the root element. @@ -222,10 +222,10 @@ export const setResolutionMethod = function (x, y) { */ export const getEditorNSMethod = function (add) { if (add) { - svgCanvas.getSvgContent().setAttribute('xmlns:se', NS.SE); + svgCanvas.getSvgContent().setAttribute('xmlns:se', NS.SE) } - return NS.SE; -}; + return NS.SE +} /** * @typedef {PlainObject} module:elem-get-set.ZoomAndBBox @@ -241,56 +241,56 @@ export const getEditorNSMethod = function (add) { * @returns {module:elem-get-set.ZoomAndBBox|void} */ export const setBBoxZoomMethod = function (val, editorW, editorH) { - const zoom = svgCanvas.getZoom(); - const selectedElements = svgCanvas.getSelectedElements(); - let spacer = 0.85; - let bb; + const zoom = svgCanvas.getZoom() + const selectedElements = svgCanvas.getSelectedElements() + let spacer = 0.85 + let bb const calcZoom = function (bb) { - 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); - svgCanvas.setZoom(zoom); - return { zoom, bbox: bb }; - }; + 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) + svgCanvas.setZoom(zoom) + return { zoom, bbox: bb } + } if (typeof val === 'object') { - bb = val; + bb = val if (bb.width === 0 || bb.height === 0) { - const newzoom = bb.zoom ? bb.zoom : zoom * bb.factor; - svgCanvas.setZoom(newzoom); - return { zoom: zoom, bbox: bb }; + const newzoom = bb.zoom ? bb.zoom : zoom * bb.factor + svgCanvas.setZoom(newzoom) + return { zoom: zoom, bbox: bb } } - return calcZoom(bb); + return calcZoom(bb) } switch (val) { - case 'selection': { - if (!selectedElements[0]) { return undefined; } - const selectedElems = selectedElements.map(function (n, _) { - if (n) { - return n; - } - return undefined; - }); - bb = getStrokedBBoxDefaultVisible(selectedElems); - break; - } case 'canvas': { - const res = svgCanvas.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(svgCanvas.getCurrentDrawing().getCurrentLayer())); - break; - default: - return undefined; + case 'selection': { + if (!selectedElements[0]) { return undefined } + const selectedElems = selectedElements.map(function (n, _) { + if (n) { + return n + } + return undefined + }) + bb = getStrokedBBoxDefaultVisible(selectedElems) + break + } case 'canvas': { + const res = svgCanvas.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(svgCanvas.getCurrentDrawing().getCurrentLayer())) + break + default: + return undefined } - return calcZoom(bb); -}; + return calcZoom(bb) +} /** * Sets the zoom to the given level. @@ -300,17 +300,17 @@ export const setBBoxZoomMethod = function (val, editorW, editorH) { * @returns {void} */ export const setZoomMethod = function (zoomLevel) { - const selectedElements = svgCanvas.getSelectedElements(); - const res = svgCanvas.getResolution(); - svgCanvas.getSvgContent().setAttribute('viewBox', '0 0 ' + res.w / zoomLevel + ' ' + res.h / zoomLevel); - svgCanvas.setZoom(zoomLevel); - selectedElements.forEach(function(elem){ - if (!elem) { return; } - svgCanvas.selectorManager.requestSelector(elem).resize(); - }); - svgCanvas.pathActions.zoomChange(); - svgCanvas.runExtensions('zoomChanged', zoomLevel); -}; + const selectedElements = svgCanvas.getSelectedElements() + const res = svgCanvas.getResolution() + svgCanvas.getSvgContent().setAttribute('viewBox', '0 0 ' + res.w / zoomLevel + ' ' + res.h / zoomLevel) + svgCanvas.setZoom(zoomLevel) + selectedElements.forEach(function (elem) { + if (!elem) { return } + svgCanvas.selectorManager.requestSelector(elem).resize() + }) + svgCanvas.pathActions.zoomChange() + svgCanvas.runExtensions('zoomChanged', zoomLevel) +} /** * Change the current stroke/fill color/gradient value. @@ -322,44 +322,44 @@ export const setZoomMethod = function (zoomLevel) { * @returns {void} */ export const setColorMethod = function (type, val, preventUndo) { - const selectedElements = svgCanvas.getSelectedElements(); - svgCanvas.setCurShape(type, val); - svgCanvas.setCurProperties(type + '_paint', { type: 'solidColor' }); - const elems = []; + const selectedElements = svgCanvas.getSelectedElements() + svgCanvas.setCurShape(type, val) + svgCanvas.setCurProperties(type + '_paint', { type: 'solidColor' }) + const elems = [] /** * * @param {Element} e * @returns {void} */ - function addNonG(e) { + function addNonG (e) { if (e.nodeName !== 'g') { - elems.push(e); + elems.push(e) } } - let i = selectedElements.length; + let i = selectedElements.length while (i--) { - const elem = selectedElements[i]; + const elem = selectedElements[i] if (elem) { if (elem.tagName === 'g') { - walkTree(elem, addNonG); + walkTree(elem, addNonG) } else if (type === 'fill') { if (elem.tagName !== 'polyline' && elem.tagName !== 'line') { - elems.push(elem); + elems.push(elem) } } else { - elems.push(elem); + elems.push(elem) } } } if (elems.length > 0) { if (!preventUndo) { - svgCanvas.changeSelectedAttribute(type, val, elems); - svgCanvas.call('changed', elems); + svgCanvas.changeSelectedAttribute(type, val, elems) + svgCanvas.call('changed', elems) } else { - svgCanvas.changeSelectedAttributeNoUndoMethod(type, val, elems); + svgCanvas.changeSelectedAttributeNoUndoMethod(type, val, elems) } } -}; +} /** * Apply the current gradient to selected element's fill or stroke. @@ -369,24 +369,24 @@ export const setColorMethod = function (type, val, preventUndo) { */ export const setGradientMethod = function (type) { if (!svgCanvas.getCurProperties(type + '_paint') || - svgCanvas.getCurProperties(type + '_paint').type === 'solidColor') { return; } - const canvas = svgCanvas; - let grad = canvas[type + 'Grad']; + svgCanvas.getCurProperties(type + '_paint').type === 'solidColor') { return } + const canvas = svgCanvas + let grad = canvas[type + 'Grad'] // find out if there is a duplicate gradient already in the defs - const duplicateGrad = findDuplicateGradient(grad); - const defs = findDefs(); + const duplicateGrad = findDuplicateGradient(grad) + const defs = findDefs() // no duplicate found, so import gradient into defs if (!duplicateGrad) { // const origGrad = grad; - grad = svgCanvas.getDOMDocument().importNode(grad, true); - defs.append(grad); + grad = svgCanvas.getDOMDocument().importNode(grad, true) + defs.append(grad) // get next id and set it on the grad - grad.id = svgCanvas.getNextId(); + grad.id = svgCanvas.getNextId() } else { // use existing gradient - grad = duplicateGrad; + grad = duplicateGrad } - svgCanvas.setColor(type, 'url(#' + grad.id + ')'); -}; + svgCanvas.setColor(type, 'url(#' + grad.id + ')') +} /** * Check if exact gradient already exists. @@ -395,19 +395,19 @@ export const setGradientMethod = function (type) { * @returns {SVGGradientElement} The existing gradient if found, `null` if not */ export const findDuplicateGradient = function (grad) { - const defs = findDefs(); - const existingGrads = defs.querySelectorAll('linearGradient, radialGradient'); - let i = existingGrads.length; - const radAttrs = [ 'r', 'cx', 'cy', 'fx', 'fy' ]; + const defs = findDefs() + const existingGrads = defs.querySelectorAll('linearGradient, radialGradient') + let i = existingGrads.length + const radAttrs = ['r', 'cx', 'cy', 'fx', 'fy'] while (i--) { - const og = existingGrads[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; + continue } } else { const gradAttrs = { @@ -416,50 +416,50 @@ export const findDuplicateGradient = function (grad) { cy: Number(grad.getAttribute('cy')), fx: Number(grad.getAttribute('fx')), fy: Number(grad.getAttribute('fy')) - }; + } const ogAttrs = { r: Number(og.getAttribute('r')), cx: Number(og.getAttribute('cx')), cy: Number(og.getAttribute('cy')), fx: Number(og.getAttribute('fx')), fy: Number(og.getAttribute('fy')) - }; + } - let diff = false; + let diff = false radAttrs.forEach(function (attr) { - if (gradAttrs[attr] !== ogAttrs[attr]) { diff = true; } - }); + if (gradAttrs[attr] !== ogAttrs[attr]) { diff = true } + }) - if (diff) { continue; } + if (diff) { continue } } // else could be a duplicate, iterate through stops - const stops = grad.getElementsByTagNameNS(NS.SVG, 'stop'); - const ostops = og.getElementsByTagNameNS(NS.SVG, 'stop'); + const stops = grad.getElementsByTagNameNS(NS.SVG, 'stop') + const ostops = og.getElementsByTagNameNS(NS.SVG, 'stop') if (stops.length !== ostops.length) { - continue; + continue } - let j = stops.length; + let j = stops.length while (j--) { - const stop = stops[j]; - const ostop = ostops[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; + break } } if (j === -1) { - return og; + return og } } // for each gradient in defs - return null; -}; + return null +} /** * Set a color/gradient to a fill/stroke. @@ -470,22 +470,22 @@ export const findDuplicateGradient = function (grad) { */ export const setPaintMethod = function (type, paint) { // make a copy - const p = new jGraduate.Paint(paint); - this.setPaintOpacity(type, p.alpha / 100, true); + const p = new jGraduate.Paint(paint) + this.setPaintOpacity(type, p.alpha / 100, true) // now set the current paint object - svgCanvas.setCurProperties(type + '_paint', p); + svgCanvas.setCurProperties(type + '_paint', p) switch (p.type) { - case 'solidColor': - this.setColor(type, p.solidColor !== 'none' ? '#' + p.solidColor : 'none'); - break; - case 'linearGradient': - case 'radialGradient': - svgCanvas.setCanvas(type + 'Grad', p[p.type]); - svgCanvas.setGradient(type); - break; + case 'solidColor': + this.setColor(type, p.solidColor !== 'none' ? '#' + p.solidColor : 'none') + break + case 'linearGradient': + case 'radialGradient': + svgCanvas.setCanvas(type + 'Grad', p[p.type]) + svgCanvas.setGradient(type) + break } -}; +} /** * 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. @@ -495,40 +495,40 @@ export const setPaintMethod = function (type, paint) { * @returns {void} */ export const setStrokeWidthMethod = function (val) { - const selectedElements = svgCanvas.getSelectedElements(); - if (val === 0 && [ 'line', 'path' ].includes(svgCanvas.getMode())) { - svgCanvas.setStrokeWidth(1); - return; + const selectedElements = svgCanvas.getSelectedElements() + if (val === 0 && ['line', 'path'].includes(svgCanvas.getMode())) { + svgCanvas.setStrokeWidth(1) + return } - svgCanvas.setCurProperties('stroke_width', val); + svgCanvas.setCurProperties('stroke_width', val) - const elems = []; + const elems = [] /** * * @param {Element} e * @returns {void} */ - function addNonG(e) { + function addNonG (e) { if (e.nodeName !== 'g') { - elems.push(e); + elems.push(e) } } - let i = selectedElements.length; + let i = selectedElements.length while (i--) { - const elem = selectedElements[i]; + const elem = selectedElements[i] if (elem) { if (elem.tagName === 'g') { - walkTree(elem, addNonG); + walkTree(elem, addNonG) } else { - elems.push(elem); + elems.push(elem) } } } if (elems.length > 0) { - svgCanvas.changeSelectedAttribute('stroke-width', val, elems); - svgCanvas.call('changed', selectedElements); + svgCanvas.changeSelectedAttribute('stroke-width', val, elems) + svgCanvas.call('changed', selectedElements) } -}; +} /** * Set the given stroke-related attribute the given value for selected elements. @@ -539,41 +539,41 @@ export const setStrokeWidthMethod = function (val) { * @returns {void} */ export const setStrokeAttrMethod = function (attr, val) { - const selectedElements = svgCanvas.getSelectedElements(); - svgCanvas.setCurShape(attr.replace('-', '_'), val); - const elems = []; + const selectedElements = svgCanvas.getSelectedElements() + svgCanvas.setCurShape(attr.replace('-', '_'), val) + const elems = [] - let i = selectedElements.length; + let i = selectedElements.length while (i--) { - const elem = selectedElements[i]; + const elem = selectedElements[i] if (elem) { if (elem.tagName === 'g') { - walkTree(elem, function (e) { if (e.nodeName !== 'g') { elems.push(e); } }); + walkTree(elem, function (e) { if (e.nodeName !== 'g') { elems.push(e) } }) } else { - elems.push(elem); + elems.push(elem) } } } if (elems.length > 0) { - svgCanvas.changeSelectedAttribute(attr, val, elems); - svgCanvas.call('changed', selectedElements); + svgCanvas.changeSelectedAttribute(attr, val, elems) + svgCanvas.call('changed', selectedElements) } -}; +} /** * Check whether selected element is bold or not. * @function module:svgcanvas.SvgCanvas#getBold * @returns {boolean} Indicates whether or not element is bold */ export const getBoldMethod = function () { - const selectedElements = svgCanvas.getSelectedElements(); + const selectedElements = svgCanvas.getSelectedElements() // should only have one element selected - const selected = selectedElements[0]; + const selected = selectedElements[0] if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { - return (selected.getAttribute('font-weight') === 'bold'); + return (selected.getAttribute('font-weight') === 'bold') } - return false; -}; + return false +} /** * Make the selected element bold or normal. @@ -582,16 +582,16 @@ export const getBoldMethod = function () { * @returns {void} */ export const setBoldMethod = function (b) { - const selectedElements = svgCanvas.getSelectedElements(); - const selected = selectedElements[0]; + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { - svgCanvas.changeSelectedAttribute('font-weight', b ? 'bold' : 'normal'); + svgCanvas.changeSelectedAttribute('font-weight', b ? 'bold' : 'normal') } if (!selectedElements[0].textContent) { - svgCanvas.textActions.setCursor(); + svgCanvas.textActions.setCursor() } -}; +} /** * Check whether selected element is in italics or not. @@ -599,14 +599,14 @@ export const setBoldMethod = function (b) { * @returns {boolean} Indicates whether or not element is italic */ export const getItalicMethod = function () { - const selectedElements = svgCanvas.getSelectedElements(); - const selected = selectedElements[0]; + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { - return (selected.getAttribute('font-style') === 'italic'); + return (selected.getAttribute('font-style') === 'italic') } - return false; -}; + return false +} /** * Make the selected element italic or normal. @@ -615,16 +615,16 @@ export const getItalicMethod = function () { * @returns {void} */ export const setItalicMethod = function (i) { - const selectedElements = svgCanvas.getSelectedElements(); - const selected = selectedElements[0]; + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { - svgCanvas.changeSelectedAttribute('font-style', i ? 'italic' : 'normal'); + svgCanvas.changeSelectedAttribute('font-style', i ? 'italic' : 'normal') } if (!selectedElements[0].textContent) { - svgCanvas.textActions.setCursor(); + svgCanvas.textActions.setCursor() } -}; +} /** * @function module:svgcanvas.SvgCanvas#setTextAnchorMethod Set the new text anchor @@ -632,24 +632,24 @@ export const setItalicMethod = function (i) { * @returns {void} */ export const setTextAnchorMethod = function (value) { - const selectedElements = svgCanvas.getSelectedElements(); - const selected = selectedElements[0]; + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { - svgCanvas.changeSelectedAttribute('text-anchor', value); + svgCanvas.changeSelectedAttribute('text-anchor', value) } if (!selectedElements[0].textContent) { - svgCanvas.textActions.setCursor(); + svgCanvas.textActions.setCursor() } -}; +} /** * @function module:svgcanvas.SvgCanvas#getFontFamily * @returns {string} The current font family */ export const getFontFamilyMethod = function () { - return svgCanvas.getCurText('font_family'); -}; + return svgCanvas.getCurText('font_family') +} /** * Set the new font family. @@ -658,13 +658,13 @@ export const getFontFamilyMethod = function () { * @returns {void} */ export const setFontFamilyMethod = function (val) { - const selectedElements = svgCanvas.getSelectedElements(); - svgCanvas.setCurText('font_family', val); - svgCanvas.changeSelectedAttribute('font-family', val); + const selectedElements = svgCanvas.getSelectedElements() + svgCanvas.setCurText('font_family', val) + svgCanvas.changeSelectedAttribute('font-family', val) if (selectedElements[0] && !selectedElements[0].textContent) { - svgCanvas.textActions.setCursor(); + svgCanvas.textActions.setCursor() } -}; +} /** * Set the new font color. @@ -673,25 +673,25 @@ export const setFontFamilyMethod = function (val) { * @returns {void} */ export const setFontColorMethod = function (val) { - svgCanvas.setCurText('fill', val); - svgCanvas.changeSelectedAttribute('fill', val); -}; + svgCanvas.setCurText('fill', val) + svgCanvas.changeSelectedAttribute('fill', val) +} /** * @function module:svgcanvas.SvgCanvas#getFontColor * @returns {string} The current font color */ export const getFontColorMethod = function () { - return svgCanvas.getCurText('fill'); -}; + return svgCanvas.getCurText('fill') +} /** * @function module:svgcanvas.SvgCanvas#getFontSize * @returns {Float} The current font size */ export const getFontSizeMethod = function () { - return svgCanvas.getCurText('font_size'); -}; + return svgCanvas.getCurText('font_size') +} /** * Applies the given font size to the selected element. @@ -700,24 +700,24 @@ export const getFontSizeMethod = function () { * @returns {void} */ export const setFontSizeMethod = function (val) { - const selectedElements = svgCanvas.getSelectedElements(); - svgCanvas.setCurText('font_size', val); - svgCanvas.changeSelectedAttribute('font-size', val); + const selectedElements = svgCanvas.getSelectedElements() + svgCanvas.setCurText('font_size', val) + svgCanvas.changeSelectedAttribute('font-size', val) if (selectedElements[0] && !selectedElements[0].textContent) { - svgCanvas.textActions.setCursor(); + svgCanvas.textActions.setCursor() } -}; +} /** * @function module:svgcanvas.SvgCanvas#getText * @returns {string} The current text (`textContent`) of the selected element */ export const getTextMethod = function () { - const selectedElements = svgCanvas.getSelectedElements(); - const selected = selectedElements[0]; - if (isNullish(selected)) { return ''; } - return (selected) ? selected.textContent : ''; -}; + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] + if (isNullish(selected)) { return '' } + return (selected) ? selected.textContent : '' +} /** * Updates the text element with the given string. @@ -726,10 +726,10 @@ export const getTextMethod = function () { * @returns {void} */ export const setTextContentMethod = function (val) { - svgCanvas.changeSelectedAttribute('#text', val); - svgCanvas.textActions.init(val); - svgCanvas.textActions.setCursor(); -}; + svgCanvas.changeSelectedAttribute('#text', val) + svgCanvas.textActions.init(val) + svgCanvas.textActions.setCursor() +} /** * Sets the new image URL for the selected image element. Updates its size if @@ -740,47 +740,47 @@ export const setTextContentMethod = function (val) { * @returns {void} */ export const setImageURLMethod = function (val) { - const { ChangeElementCommand, BatchCommand } = svgCanvas.history; - const selectedElements = svgCanvas.getSelectedElements(); - const elem = selectedElements[0]; - if (!elem) { return; } + const { ChangeElementCommand, BatchCommand } = svgCanvas.history + const selectedElements = svgCanvas.getSelectedElements() + const elem = selectedElements[0] + if (!elem) { return } const attrs = { width: elem.getAttribute('width'), height: elem.getAttribute('height') - }; - const setsize = (!attrs.width || !attrs.height); + } + const setsize = (!attrs.width || !attrs.height) - const curHref = getHref(elem); + const curHref = getHref(elem) // Do nothing if no URL change or size change if (curHref === val && !setsize) { - return; + return } - const batchCmd = new BatchCommand('Change Image URL'); + const batchCmd = new BatchCommand('Change Image URL') - setHref(elem, val); + setHref(elem, val) batchCmd.addSubCommand(new ChangeElementCommand(elem, { '#href': curHref - })); - const img = new Image(); + })) + const img = new Image() img.onload = function () { const changes = { width: elem.getAttribute('width'), height: elem.getAttribute('height') - }; - elem.setAttribute('width', this.width); - elem.setAttribute('height', this.height); + } + elem.setAttribute('width', this.width) + elem.setAttribute('height', this.height) - svgCanvas.selectorManager.requestSelector(elem).resize(); + svgCanvas.selectorManager.requestSelector(elem).resize() - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - svgCanvas.addCommandToHistory(batchCmd); - svgCanvas.call('changed', [ elem ]); - }; - img.src = val; -}; + batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)) + svgCanvas.addCommandToHistory(batchCmd) + svgCanvas.call('changed', [elem]) + } + img.src = val +} /** * Sets the new link URL for the selected anchor element. @@ -789,33 +789,33 @@ export const setImageURLMethod = function (val) { * @returns {void} */ export const setLinkURLMethod = function (val) { - const { ChangeElementCommand, BatchCommand } = svgCanvas.history; - const selectedElements = svgCanvas.getSelectedElements(); - let elem = selectedElements[0]; - if (!elem) { return; } + const { ChangeElementCommand, BatchCommand } = svgCanvas.history + const selectedElements = svgCanvas.getSelectedElements() + let elem = selectedElements[0] + if (!elem) { return } if (elem.tagName !== 'a') { // See if parent is an anchor - const parentsA = getParents(elem.parentNode, 'a'); + const parentsA = getParents(elem.parentNode, 'a') if (parentsA?.length) { - elem = parentsA[0]; + elem = parentsA[0] } else { - return; + return } } - const curHref = getHref(elem); + const curHref = getHref(elem) - if (curHref === val) { return; } + if (curHref === val) { return } - const batchCmd = new BatchCommand('Change Link URL'); + const batchCmd = new BatchCommand('Change Link URL') - setHref(elem, val); + setHref(elem, val) batchCmd.addSubCommand(new ChangeElementCommand(elem, { '#href': curHref - })); + })) - svgCanvas.addCommandToHistory(batchCmd); -}; + svgCanvas.addCommandToHistory(batchCmd) +} /** * Sets the `rx` and `ry` values to the selected `rect` element @@ -826,19 +826,19 @@ export const setLinkURLMethod = function (val) { * @returns {void} */ export const setRectRadiusMethod = function (val) { - const { ChangeElementCommand } = svgCanvas.history; - const selectedElements = svgCanvas.getSelectedElements(); - const selected = selectedElements[0]; + const { ChangeElementCommand } = svgCanvas.history + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] if (!isNullish(selected) && selected.tagName === 'rect') { - const r = Number(selected.getAttribute('rx')); + const r = Number(selected.getAttribute('rx')) if (r !== val) { - selected.setAttribute('rx', val); - selected.setAttribute('ry', val); - svgCanvas.addCommandToHistory(new ChangeElementCommand(selected, { rx: r, ry: r }, 'Radius')); - svgCanvas.call('changed', [ selected ]); + selected.setAttribute('rx', val) + selected.setAttribute('ry', val) + svgCanvas.addCommandToHistory(new ChangeElementCommand(selected, { rx: r, ry: r }, 'Radius')) + svgCanvas.call('changed', [selected]) } } -}; +} /** * Wraps the selected element(s) in an anchor element or converts group to one. @@ -847,19 +847,19 @@ export const setRectRadiusMethod = function (val) { * @returns {void} */ export const makeHyperlinkMethod = function (url) { - svgCanvas.groupSelectedElements('a', url); + svgCanvas.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} */ export const removeHyperlinkMethod = function () { - svgCanvas.ungroupSelectedElement(); -}; + svgCanvas.ungroupSelectedElement() +} /** * Group: Element manipulation. @@ -872,8 +872,8 @@ export const removeHyperlinkMethod = function () { * @returns {void} */ export const setSegTypeMethod = function (newType) { - svgCanvas.pathActions.setSegType(newType); -}; + svgCanvas.pathActions.setSegType(newType) +} /** * Set the background of the editor (NOT the actual document). @@ -883,48 +883,48 @@ export const setSegTypeMethod = function (newType) { * @returns {void} */ export const setBackgroundMethod = function (color, url) { - const bg = getElem('canvasBackground'); - const border = bg.querySelector('rect'); - let bgImg = getElem('background_image'); - let bgPattern = getElem('background_pattern'); - border.setAttribute('fill', color === 'chessboard' ? '#fff' : color); + const bg = getElem('canvasBackground') + const border = bg.querySelector('rect') + let bgImg = getElem('background_image') + let bgPattern = getElem('background_pattern') + border.setAttribute('fill', color === 'chessboard' ? '#fff' : color) if (color === 'chessboard') { if (!bgPattern) { - bgPattern = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'foreignObject'); + bgPattern = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'foreignObject') svgCanvas.assignAttributes(bgPattern, { id: 'background_pattern', width: '100%', height: '100%', preserveAspectRatio: 'xMinYMin', style: 'pointer-events:none' - }); - const div = document.createElement('div'); + }) + const div = document.createElement('div') svgCanvas.assignAttributes(div, { style: 'pointer-events:none;width:100%;height:100%;' + 'background-image:url(data:image/gif;base64,' + 'R0lGODlhEAAQAIAAAP///9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG+' + 'gq4jM3IFLJgpswNly/XkcBpIiVaInlLJr9FZWAQA7);' - }); - bgPattern.append(div); - bg.append(bgPattern); + }) + bgPattern.append(div) + bg.append(bgPattern) } } else if (bgPattern) { - bgPattern.remove(); + bgPattern.remove() } if (url) { if (!bgImg) { - bgImg = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'image'); + bgImg = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'image') svgCanvas.assignAttributes(bgImg, { id: 'background_image', width: '100%', height: '100%', preserveAspectRatio: 'xMinYMin', style: 'pointer-events:none' - }); + }) } - setHref(bgImg, url); - bg.append(bgImg); + setHref(bgImg, url) + bg.append(bgImg) } else if (bgImg) { - bgImg.remove(); + bgImg.remove() } -}; +} diff --git a/src/svgcanvas/event.js b/src/svgcanvas/event.js index 664a148d..0407d964 100644 --- a/src/svgcanvas/event.js +++ b/src/svgcanvas/event.js @@ -7,23 +7,23 @@ import { assignAttributes, cleanupElement, getElem, getRotationAngle, snapToGrid, walkTree, isNullish, preventClickDefault, setHref, getBBox -} from './utilities.js'; +} from './utilities.js' import { convertAttrs -} from '../common/units.js'; +} from '../common/units.js' import { transformPoint, hasMatrixTransform, getMatrix, snapToAngle -} from './math.js'; -import * as draw from './draw.js'; -import * as pathModule from './path.js'; -import * as hstry from './history.js'; -import { findPos } from '../editor/components/jgraduate/Util.js'; +} from './math.js' +import * as draw from './draw.js' +import * as pathModule from './path.js' +import * as hstry from './history.js' +import { findPos } from '../editor/components/jgraduate/Util.js' const { InsertElementCommand -} = hstry; +} = hstry -let svgCanvas = null; +let svgCanvas = null /** * @function module:undo.init @@ -31,44 +31,44 @@ let svgCanvas = null; * @returns {void} */ export const init = (canvas) => { - svgCanvas = canvas; -}; + svgCanvas = canvas +} export const getBsplinePoint = (t) => { - const spline = { x: 0, y: 0 }; - const p0 = { x: svgCanvas.getControllPoint2('x'), y: svgCanvas.getControllPoint2('y') }; - const p1 = { x: svgCanvas.getControllPoint1('x'), y: svgCanvas.getControllPoint1('y') }; - const p2 = { x: svgCanvas.getStart('x'), y: svgCanvas.getStart('y') }; - const p3 = { x: svgCanvas.getEnd('x'), y: svgCanvas.getEnd('y') }; - const S = 1.0 / 6.0; - const t2 = t * t; - const t3 = t2 * t; + const spline = { x: 0, y: 0 } + const p0 = { x: svgCanvas.getControllPoint2('x'), y: svgCanvas.getControllPoint2('y') } + const p1 = { x: svgCanvas.getControllPoint1('x'), y: svgCanvas.getControllPoint1('y') } + const p2 = { x: svgCanvas.getStart('x'), y: svgCanvas.getStart('y') } + const p3 = { x: svgCanvas.getEnd('x'), y: svgCanvas.getEnd('y') } + const S = 1.0 / 6.0 + const t2 = t * t + const t3 = t2 * t const m = [ - [ -1, 3, -3, 1 ], - [ 3, -6, 3, 0 ], - [ -3, 0, 3, 0 ], - [ 1, 4, 1, 0 ] - ]; + [-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 - }; -}; + } +} /** * @@ -78,426 +78,426 @@ export const getBsplinePoint = (t) => { * @returns {void} */ export const mouseMoveEvent = (evt) => { - const selectedElements = svgCanvas.getSelectedElements(); - const zoom = svgCanvas.getZoom(); - const svgRoot = svgCanvas.getSvgRoot(); + const selectedElements = svgCanvas.getSelectedElements() + const zoom = svgCanvas.getZoom() + const svgRoot = svgCanvas.getSvgRoot() - if (!svgCanvas.getStarted()) { return; } - if (evt.button === 1 || svgCanvas.spaceKey) { return; } + if (!svgCanvas.getStarted()) { return } + if (evt.button === 1 || svgCanvas.spaceKey) { return } - let i; - let xya; - let cx; - let cy; - let dx; - let dy; - let len; - let angle; - let box; - let selected = selectedElements[0]; - const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()); - const mouseX = pt.x * zoom; - const mouseY = pt.y * zoom; - const shape = getElem(svgCanvas.getId()); + let i + let xya + let cx + let cy + let dx + let dy + let len + let angle + let box + let selected = selectedElements[0] + const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()) + const mouseX = pt.x * zoom + const mouseY = pt.y * zoom + const shape = getElem(svgCanvas.getId()) - let realX = mouseX / zoom; - let x = realX; - let realY = mouseY / zoom; - let y = realY; + let realX = mouseX / zoom + let x = realX + let realY = mouseY / zoom + let y = realY if (svgCanvas.getCurConfig().gridSnapping) { - x = snapToGrid(x); - y = snapToGrid(y); + x = snapToGrid(x) + y = snapToGrid(y) } - evt.preventDefault(); - let tlist; + evt.preventDefault() + let tlist switch (svgCanvas.getCurrentMode()) { - case 'select': { + 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 - svgCanvas.getStartX(); - dy = y - svgCanvas.getStartY(); - if (svgCanvas.getCurConfig().gridSnapping) { - dx = snapToGrid(dx); - dy = snapToGrid(dy); - } - - if (dx !== 0 || dy !== 0) { - len = selectedElements.length; - for (i = 0; i < len; ++i) { - selected = selectedElements[i]; - if (isNullish(selected)) { break; } - // update the dummy transform in our transform list - // to be a translate - const xform = svgRoot.createSVGTransform(); - tlist = selected.transform?.baseVal; - // 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 - svgCanvas.selectorManager.requestSelector(selected).resize(); + if (selectedElements[0] !== null) { + dx = x - svgCanvas.getStartX() + dy = y - svgCanvas.getStartY() + if (svgCanvas.getCurConfig().gridSnapping) { + dx = snapToGrid(dx) + dy = snapToGrid(dy) } - svgCanvas.call('transition', selectedElements); + if (dx !== 0 || dy !== 0) { + len = selectedElements.length + for (i = 0; i < len; ++i) { + selected = selectedElements[i] + if (isNullish(selected)) { break } + // update the dummy transform in our transform list + // to be a translate + const xform = svgRoot.createSVGTransform() + tlist = selected.transform?.baseVal + // 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 + svgCanvas.selectorManager.requestSelector(selected).resize() + } + + svgCanvas.call('transition', selectedElements) + } } - } - break; - } case 'multiselect': { - realX *= zoom; - realY *= zoom; - assignAttributes(svgCanvas.getRubberBox(), { - x: Math.min(svgCanvas.getRStartX(), realX), - y: Math.min(svgCanvas.getRStartY(), realY), - width: Math.abs(realX - svgCanvas.getRStartX()), - height: Math.abs(realY - svgCanvas.getRStartY()) - }, 100); + break + } case 'multiselect': { + realX *= zoom + realY *= zoom + assignAttributes(svgCanvas.getRubberBox(), { + x: Math.min(svgCanvas.getRStartX(), realX), + y: Math.min(svgCanvas.getRStartY(), realY), + width: Math.abs(realX - svgCanvas.getRStartX()), + height: Math.abs(realY - svgCanvas.getRStartY()) + }, 100) - // 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(); const elemsToAdd = []; - const newList = svgCanvas.getIntersectionList(); + // 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(); const elemsToAdd = [] + const newList = svgCanvas.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); + // 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) + } } - // 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) { + svgCanvas.removeFromSelection(elemsToRemove) } - } - if (elemsToRemove.length > 0) { - svgCanvas.removeFromSelection(elemsToRemove); - } + if (elemsToAdd.length > 0) { + svgCanvas.addToSelection(elemsToAdd) + } - if (elemsToAdd.length > 0) { - svgCanvas.addToSelection(elemsToAdd); - } - - break; - } case 'resize': { + 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 = selected.transform.baseVal; - const hasMatrix = hasMatrixTransform(tlist); - box = hasMatrix ? svgCanvas.getInitBbox() : getBBox(selected); - let left = box.x; - let top = box.y; - let { width, height } = box; - dx = (x - svgCanvas.getStartX()); - dy = (y - svgCanvas.getStartY()); + tlist = selected.transform.baseVal + const hasMatrix = hasMatrixTransform(tlist) + box = hasMatrix ? svgCanvas.getInitBbox() : getBBox(selected) + let left = box.x + let top = box.y + let { width, height } = box + dx = (x - svgCanvas.getStartX()) + dy = (y - svgCanvas.getStartY()) - if (svgCanvas.getCurConfig().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); - const 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 (!svgCanvas.getCurrentResizeMode().includes('n') && !svgCanvas.getCurrentResizeMode().includes('s')) { - dy = 0; - } - if (!svgCanvas.getCurrentResizeMode().includes('e') && !svgCanvas.getCurrentResizeMode().includes('w')) { - dx = 0; - } - - let // ts = null, - tx = 0; let ty = 0; - let sy = height ? (height + dy) / height : 1; - let sx = width ? (width + dx) / width : 1; - // if we are dragging on the north side, then adjust the scale factor and ty - if (svgCanvas.getCurrentResizeMode().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 (svgCanvas.getCurrentResizeMode().includes('w')) { - sx = width ? (width - dx) / width : 1; - tx = width; - } - - // update the transform list with translate,scale,translate - const translateOrigin = svgRoot.createSVGTransform(); - const scale = svgRoot.createSVGTransform(); - const translateBack = svgRoot.createSVGTransform(); - - if (svgCanvas.getCurConfig().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) { - const diff = angle ? 1 : 0; - tlist.replaceItem(translateOrigin, 2 + diff); - tlist.replaceItem(scale, 1 + diff); - tlist.replaceItem(translateBack, Number(diff)); - } else { - const N = tlist.numberOfItems; - tlist.replaceItem(translateBack, N - 3); - tlist.replaceItem(scale, N - 2); - tlist.replaceItem(translateOrigin, N - 1); - } - - svgCanvas.selectorManager.requestSelector(selected).resize(); - svgCanvas.call('transition', selectedElements); - - break; - } case 'zoom': { - realX *= zoom; - realY *= zoom; - assignAttributes(svgCanvas.getRubberBox(), { - x: Math.min(svgCanvas.getRStartX() * zoom, realX), - y: Math.min(svgCanvas.getRStartY() * zoom, realY), - width: Math.abs(realX - svgCanvas.getRStartX() * zoom), - height: Math.abs(realY - svgCanvas.getRStartY() * zoom) - }, 100); - break; - } case 'text': { - assignAttributes(shape, { - x, - y - }, 1000); - break; - } case 'line': { - if (svgCanvas.getCurConfig().gridSnapping) { - x = snapToGrid(x); - y = snapToGrid(y); - } - - let x2 = x; - let y2 = y; - - if (evt.shiftKey) { - xya = snapToAngle(svgCanvas.getStartX(), svgCanvas.getStartY(), 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': { - const square = (svgCanvas.getCurrentMode() === 'square') || evt.shiftKey; - let - w = Math.abs(x - svgCanvas.getStartX()); - let h = Math.abs(y - svgCanvas.getStartY()); - let newX; let newY; - if (square) { - w = h = Math.max(w, h); - newX = svgCanvas.getStartX() < x ? svgCanvas.getStartX() : svgCanvas.getStartX() - w; - newY = svgCanvas.getStartY() < y ? svgCanvas.getStartY() : svgCanvas.getStartY() - h; - } else { - newX = Math.min(svgCanvas.getStartX(), x); - newY = Math.min(svgCanvas.getStartY(), y); - } - - if (svgCanvas.getCurConfig().gridSnapping) { - w = snapToGrid(w); - h = snapToGrid(h); - newX = snapToGrid(newX); - newY = snapToGrid(newY); - } - - assignAttributes(shape, { - width: w, - height: h, - x: newX, - y: newY - }, 1000); - - break; - } case 'circle': { - cx = Number(shape.getAttribute('cx')); - cy = Number(shape.getAttribute('cy')); - let rad = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)); - if (svgCanvas.getCurConfig().gridSnapping) { - rad = snapToGrid(rad); - } - shape.setAttribute('r', rad); - break; - } case 'ellipse': { - cx = Number(shape.getAttribute('cx')); - cy = Number(shape.getAttribute('cy')); - if (svgCanvas.getCurConfig().gridSnapping) { - x = snapToGrid(x); - cx = snapToGrid(cx); - y = snapToGrid(y); - cy = snapToGrid(cy); - } - shape.setAttribute('rx', Math.abs(x - cx)); - const ry = Math.abs(evt.shiftKey ? (x - cx) : (y - cy)); - shape.setAttribute('ry', ry); - break; - } - case 'fhellipse': - case 'fhrect': { - svgCanvas.setFreehand('minx', Math.min(realX, svgCanvas.getFreehand('minx'))); - svgCanvas.setFreehand('maxx', Math.max(realX, svgCanvas.getFreehand('maxx'))); - svgCanvas.setFreehand('miny', Math.min(realY, svgCanvas.getFreehand('miny'))); - svgCanvas.setFreehand('maxy', Math.max(realY, svgCanvas.getFreehand('maxy'))); - } - // Fallthrough - case 'fhpath': { - // dAttr += + realX + ',' + realY + ' '; - // shape.setAttribute('points', dAttr); - svgCanvas.setEnd('x', realX); - svgCanvas.setEnd('y', realY); - if (svgCanvas.getControllPoint2('x') && svgCanvas.getControllPoint2('y')) { - for (i = 0; i < svgCanvas.getStepCount() - 1; i++) { - svgCanvas.setParameter(i / svgCanvas.getStepCount()); - svgCanvas.setNextParameter((i + 1) / svgCanvas.getStepCount()); - svgCanvas.setbSpline(getBsplinePoint(svgCanvas.getNextParameter())); - svgCanvas.setNextPos({ x: svgCanvas.getbSpline('x'), y: svgCanvas.getbSpline('y') }); - svgCanvas.setbSpline(getBsplinePoint(svgCanvas.getParameter())); - svgCanvas.setSumDistance( - svgCanvas.getSumDistance() + Math.sqrt((svgCanvas.getNextPos('x') - - svgCanvas.getbSpline('x')) * (svgCanvas.getNextPos('x') - - svgCanvas.getbSpline('x')) + (svgCanvas.getNextPos('y') - - svgCanvas.getbSpline('y')) * (svgCanvas.getNextPos('y') - svgCanvas.getbSpline('y'))) - ); - if (svgCanvas.getSumDistance() > svgCanvas.getThreSholdDist()) { - svgCanvas.setSumDistance(svgCanvas.getSumDistance() - svgCanvas.getThreSholdDist()); - - // Faster than completely re-writing the points attribute. - const point = svgCanvas.getSvgContent().createSVGPoint(); - point.x = svgCanvas.getbSpline('x'); - point.y = svgCanvas.getbSpline('y'); - shape.points.appendItem(point); - } + if (svgCanvas.getCurConfig().gridSnapping) { + dx = snapToGrid(dx) + dy = snapToGrid(dy) + height = snapToGrid(height) + width = snapToGrid(width) } - } - svgCanvas.setControllPoint2('x', svgCanvas.getControllPoint1('x')); - svgCanvas.setControllPoint2('y', svgCanvas.getControllPoint1('y')); - svgCanvas.setControllPoint1('x', svgCanvas.getStart('x')); - svgCanvas.setControllPoint1('y', svgCanvas.getStart('y')); - svgCanvas.setStart({ x: svgCanvas.getEnd('x'), y: svgCanvas.getEnd('y') }); - break; - // update path stretch line coordinates - } case 'path': - // fall through - case 'pathedit': { - x *= zoom; - y *= zoom; - if (svgCanvas.getCurConfig().gridSnapping) { - x = snapToGrid(x); - y = snapToGrid(y); - svgCanvas.setStartX(snapToGrid(svgCanvas.getStartX())); - svgCanvas.setStartY(snapToGrid(svgCanvas.getStartY())); - } - if (evt.shiftKey) { - const { path } = pathModule; - let x1; let y1; - if (path) { - x1 = path.dragging ? path.dragging[0] : svgCanvas.getStartX(); - y1 = path.dragging ? path.dragging[1] : svgCanvas.getStartY(); + // if rotated, adjust the dx,dy values + angle = getRotationAngle(selected) + if (angle) { + const r = Math.sqrt(dx * dx + dy * dy) + const 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 (!svgCanvas.getCurrentResizeMode().includes('n') && !svgCanvas.getCurrentResizeMode().includes('s')) { + dy = 0 + } + if (!svgCanvas.getCurrentResizeMode().includes('e') && !svgCanvas.getCurrentResizeMode().includes('w')) { + dx = 0 + } + + let // ts = null, + tx = 0; let ty = 0 + let sy = height ? (height + dy) / height : 1 + let sx = width ? (width + dx) / width : 1 + // if we are dragging on the north side, then adjust the scale factor and ty + if (svgCanvas.getCurrentResizeMode().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 (svgCanvas.getCurrentResizeMode().includes('w')) { + sx = width ? (width - dx) / width : 1 + tx = width + } + + // update the transform list with translate,scale,translate + const translateOrigin = svgRoot.createSVGTransform() + const scale = svgRoot.createSVGTransform() + const translateBack = svgRoot.createSVGTransform() + + if (svgCanvas.getCurConfig().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) { + const diff = angle ? 1 : 0 + tlist.replaceItem(translateOrigin, 2 + diff) + tlist.replaceItem(scale, 1 + diff) + tlist.replaceItem(translateBack, Number(diff)) } else { - x1 = svgCanvas.getStartX(); - y1 = svgCanvas.getStartY(); + 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); - ({ x, y } = xya); - } - if (svgCanvas.getRubberBox() && svgCanvas.getRubberBox().getAttribute('display') !== 'none') { - realX *= zoom; - realY *= zoom; + svgCanvas.selectorManager.requestSelector(selected).resize() + svgCanvas.call('transition', selectedElements) + + break + } case 'zoom': { + realX *= zoom + realY *= zoom assignAttributes(svgCanvas.getRubberBox(), { x: Math.min(svgCanvas.getRStartX() * zoom, realX), y: Math.min(svgCanvas.getRStartY() * zoom, realY), width: Math.abs(realX - svgCanvas.getRStartX() * zoom), height: Math.abs(realY - svgCanvas.getRStartY() * zoom) - }, 100); + }, 100) + break + } case 'text': { + assignAttributes(shape, { + x, + y + }, 1000) + break + } case 'line': { + if (svgCanvas.getCurConfig().gridSnapping) { + x = snapToGrid(x) + y = snapToGrid(y) + } + + let x2 = x + let y2 = y + + if (evt.shiftKey) { + xya = snapToAngle(svgCanvas.getStartX(), svgCanvas.getStartY(), 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': { + const square = (svgCanvas.getCurrentMode() === 'square') || evt.shiftKey + let + w = Math.abs(x - svgCanvas.getStartX()) + let h = Math.abs(y - svgCanvas.getStartY()) + let newX; let newY + if (square) { + w = h = Math.max(w, h) + newX = svgCanvas.getStartX() < x ? svgCanvas.getStartX() : svgCanvas.getStartX() - w + newY = svgCanvas.getStartY() < y ? svgCanvas.getStartY() : svgCanvas.getStartY() - h + } else { + newX = Math.min(svgCanvas.getStartX(), x) + newY = Math.min(svgCanvas.getStartY(), y) + } + + if (svgCanvas.getCurConfig().gridSnapping) { + w = snapToGrid(w) + h = snapToGrid(h) + newX = snapToGrid(newX) + newY = snapToGrid(newY) + } + + assignAttributes(shape, { + width: w, + height: h, + x: newX, + y: newY + }, 1000) + + break + } case 'circle': { + cx = Number(shape.getAttribute('cx')) + cy = Number(shape.getAttribute('cy')) + let rad = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)) + if (svgCanvas.getCurConfig().gridSnapping) { + rad = snapToGrid(rad) + } + shape.setAttribute('r', rad) + break + } case 'ellipse': { + cx = Number(shape.getAttribute('cx')) + cy = Number(shape.getAttribute('cy')) + if (svgCanvas.getCurConfig().gridSnapping) { + x = snapToGrid(x) + cx = snapToGrid(cx) + y = snapToGrid(y) + cy = snapToGrid(cy) + } + shape.setAttribute('rx', Math.abs(x - cx)) + const ry = Math.abs(evt.shiftKey ? (x - cx) : (y - cy)) + shape.setAttribute('ry', ry) + break } - svgCanvas.pathActions.mouseMove(x, y); - - break; - } case 'textedit': { - x *= zoom; - y *= zoom; - // if (svgCanvas.getRubberBox() && svgCanvas.getRubberBox().getAttribute('display') !== 'none') { - // assignAttributes(svgCanvas.getRubberBox(), { - // x: Math.min(svgCanvas.getStartX(), x), - // y: Math.min(svgCanvas.getStartY(), y), - // width: Math.abs(x - svgCanvas.getStartX()), - // height: Math.abs(y - svgCanvas.getStartY()) - // }, 100); - // } - - svgCanvas.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); - const center = transformPoint(cx, cy, m); - cx = center.x; - cy = center.y; - angle = ((Math.atan2(cy - y, cx - x) * (180 / Math.PI)) - 90) % 360; - if (svgCanvas.getCurConfig().gridSnapping) { - angle = snapToGrid(angle); - } - if (evt.shiftKey) { // restrict rotations to nice angles (WRS) - const snap = 45; - angle = Math.round(angle / snap) * snap; + case 'fhellipse': + case 'fhrect': { + svgCanvas.setFreehand('minx', Math.min(realX, svgCanvas.getFreehand('minx'))) + svgCanvas.setFreehand('maxx', Math.max(realX, svgCanvas.getFreehand('maxx'))) + svgCanvas.setFreehand('miny', Math.min(realY, svgCanvas.getFreehand('miny'))) + svgCanvas.setFreehand('maxy', Math.max(realY, svgCanvas.getFreehand('maxy'))) } + // Fallthrough + case 'fhpath': { + // dAttr += + realX + ',' + realY + ' '; + // shape.setAttribute('points', dAttr); + svgCanvas.setEnd('x', realX) + svgCanvas.setEnd('y', realY) + if (svgCanvas.getControllPoint2('x') && svgCanvas.getControllPoint2('y')) { + for (i = 0; i < svgCanvas.getStepCount() - 1; i++) { + svgCanvas.setParameter(i / svgCanvas.getStepCount()) + svgCanvas.setNextParameter((i + 1) / svgCanvas.getStepCount()) + svgCanvas.setbSpline(getBsplinePoint(svgCanvas.getNextParameter())) + svgCanvas.setNextPos({ x: svgCanvas.getbSpline('x'), y: svgCanvas.getbSpline('y') }) + svgCanvas.setbSpline(getBsplinePoint(svgCanvas.getParameter())) + svgCanvas.setSumDistance( + svgCanvas.getSumDistance() + Math.sqrt((svgCanvas.getNextPos('x') - + svgCanvas.getbSpline('x')) * (svgCanvas.getNextPos('x') - + svgCanvas.getbSpline('x')) + (svgCanvas.getNextPos('y') - + svgCanvas.getbSpline('y')) * (svgCanvas.getNextPos('y') - svgCanvas.getbSpline('y'))) + ) + if (svgCanvas.getSumDistance() > svgCanvas.getThreSholdDist()) { + svgCanvas.setSumDistance(svgCanvas.getSumDistance() - svgCanvas.getThreSholdDist()) - svgCanvas.setRotationAngle(angle < -180 ? (360 + angle) : angle, true); - svgCanvas.call('transition', selectedElements); - break; - } default: - break; + // Faster than completely re-writing the points attribute. + const point = svgCanvas.getSvgContent().createSVGPoint() + point.x = svgCanvas.getbSpline('x') + point.y = svgCanvas.getbSpline('y') + shape.points.appendItem(point) + } + } + } + svgCanvas.setControllPoint2('x', svgCanvas.getControllPoint1('x')) + svgCanvas.setControllPoint2('y', svgCanvas.getControllPoint1('y')) + svgCanvas.setControllPoint1('x', svgCanvas.getStart('x')) + svgCanvas.setControllPoint1('y', svgCanvas.getStart('y')) + svgCanvas.setStart({ x: svgCanvas.getEnd('x'), y: svgCanvas.getEnd('y') }) + break + // update path stretch line coordinates + } case 'path': + // fall through + case 'pathedit': { + x *= zoom + y *= zoom + + if (svgCanvas.getCurConfig().gridSnapping) { + x = snapToGrid(x) + y = snapToGrid(y) + svgCanvas.setStartX(snapToGrid(svgCanvas.getStartX())) + svgCanvas.setStartY(snapToGrid(svgCanvas.getStartY())) + } + if (evt.shiftKey) { + const { path } = pathModule + let x1; let y1 + if (path) { + x1 = path.dragging ? path.dragging[0] : svgCanvas.getStartX() + y1 = path.dragging ? path.dragging[1] : svgCanvas.getStartY() + } else { + x1 = svgCanvas.getStartX() + y1 = svgCanvas.getStartY() + } + xya = snapToAngle(x1, y1, x, y); + ({ x, y } = xya) + } + + if (svgCanvas.getRubberBox() && svgCanvas.getRubberBox().getAttribute('display') !== 'none') { + realX *= zoom + realY *= zoom + assignAttributes(svgCanvas.getRubberBox(), { + x: Math.min(svgCanvas.getRStartX() * zoom, realX), + y: Math.min(svgCanvas.getRStartY() * zoom, realY), + width: Math.abs(realX - svgCanvas.getRStartX() * zoom), + height: Math.abs(realY - svgCanvas.getRStartY() * zoom) + }, 100) + } + svgCanvas.pathActions.mouseMove(x, y) + + break + } case 'textedit': { + x *= zoom + y *= zoom + // if (svgCanvas.getRubberBox() && svgCanvas.getRubberBox().getAttribute('display') !== 'none') { + // assignAttributes(svgCanvas.getRubberBox(), { + // x: Math.min(svgCanvas.getStartX(), x), + // y: Math.min(svgCanvas.getStartY(), y), + // width: Math.abs(x - svgCanvas.getStartX()), + // height: Math.abs(y - svgCanvas.getStartY()) + // }, 100); + // } + + svgCanvas.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) + const center = transformPoint(cx, cy, m) + cx = center.x + cy = center.y + angle = ((Math.atan2(cy - y, cx - x) * (180 / Math.PI)) - 90) % 360 + if (svgCanvas.getCurConfig().gridSnapping) { + angle = snapToGrid(angle) + } + if (evt.shiftKey) { // restrict rotations to nice angles (WRS) + const snap = 45 + angle = Math.round(angle / snap) * snap + } + + svgCanvas.setRotationAngle(angle < -180 ? (360 + angle) : angle, true) + svgCanvas.call('transition', selectedElements) + break + } default: + break } /** @@ -514,20 +514,20 @@ export const mouseMoveEvent = (evt) => { mouse_x: mouseX, mouse_y: mouseY, selected - }); -}; // mouseMove() + }) +} // mouseMove() /** * * @returns {void} */ export const mouseOutEvent = () => { - const { $id } = svgCanvas; - if(svgCanvas.getCurrentMode() !== 'select' && svgCanvas.getStarted()) { - const event = new Event("mouseup"); - $id('svgcanvas').dispatchEvent(event); + const { $id } = svgCanvas + if (svgCanvas.getCurrentMode() !== 'select' && svgCanvas.getStarted()) { + const event = new Event('mouseup') + $id('svgcanvas').dispatchEvent(event) } -}; +} // - in create mode, the element's opacity is set properly, we create an InsertElementCommand // and store it on the Undo stack @@ -543,234 +543,233 @@ export const mouseOutEvent = () => { * @returns {void} */ export const mouseUpEvent = (evt) => { - const selectedElements = svgCanvas.getSelectedElements(); - const zoom = svgCanvas.getZoom(); - if (evt.button === 2) { return; } - const tempJustSelected = svgCanvas.getJustSelected(); - svgCanvas.setJustSelected(null); - if (!svgCanvas.getStarted()) { return; } - const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()); - const mouseX = pt.x * zoom; - const mouseY = pt.y * zoom; - const x = mouseX / zoom; - const y = mouseY / zoom; + const selectedElements = svgCanvas.getSelectedElements() + const zoom = svgCanvas.getZoom() + if (evt.button === 2) { return } + const tempJustSelected = svgCanvas.getJustSelected() + svgCanvas.setJustSelected(null) + if (!svgCanvas.getStarted()) { return } + const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()) + const mouseX = pt.x * zoom + const mouseY = pt.y * zoom + const x = mouseX / zoom + const y = mouseY / zoom - let element = getElem(svgCanvas.getId()); - let keep = false; + let element = getElem(svgCanvas.getId()) + let keep = false - const realX = x; - const realY = y; + const realX = x + const realY = y // TODO: Make true when in multi-unit mode - const useUnit = false; // (svgCanvas.getCurConfig().baseUnit !== 'px'); - svgCanvas.setStarted(false); - let t; + const useUnit = false // (svgCanvas.getCurConfig().baseUnit !== 'px'); + svgCanvas.setStarted(false) + let t switch (svgCanvas.getCurrentMode()) { // intentionally fall-through to select here - case 'resize': - case 'multiselect': - if (svgCanvas.getRubberBox()) { - svgCanvas.getRubberBox().setAttribute('display', 'none'); - svgCanvas.setCurBBoxes([]); - } - svgCanvas.setCurrentMode('select'); - // Fallthrough - case 'select': - if (selectedElements[0]) { - // if we only have one selected element - if (!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: - svgCanvas.setCurProperties('fill', selected.getAttribute('fill')); - svgCanvas.setCurProperties('fill_opacity', selected.getAttribute('fill-opacity')); - svgCanvas.setCurProperties('stroke', selected.getAttribute('stroke')); - svgCanvas.setCurProperties('stroke_opacity', selected.getAttribute('stroke-opacity')); - svgCanvas.setCurProperties('stroke_width', selected.getAttribute('stroke-width')); - svgCanvas.setCurProperties('stroke_dasharray', selected.getAttribute('stroke-dasharray')); - svgCanvas.setCurProperties('stroke_linejoin', selected.getAttribute('stroke-linejoin')); - svgCanvas.setCurProperties('stroke_linecap', selected.getAttribute('stroke-linecap')); - } - - if (selected.tagName === 'text') { - svgCanvas.setCurText('font_size', selected.getAttribute('font-size')); - svgCanvas.setCurText('font_family', selected.getAttribute('font-family')); - } - svgCanvas.selectorManager.requestSelector(selected).showGrips(true); + case 'resize': + case 'multiselect': + if (svgCanvas.getRubberBox()) { + svgCanvas.getRubberBox().setAttribute('display', 'none') + svgCanvas.setCurBBoxes([]) } - // always recalculate dimensions to strip off stray identity transforms - svgCanvas.recalculateAllSelectedDimensions(); - // if it was being dragged/resized - if (realX !== svgCanvas.getRStartX() || realY !== svgCanvas.getRStartY()) { - const len = selectedElements.length; - for (let i = 0; i < len; ++i) { - if (isNullish(selectedElements[i])) { break; } + svgCanvas.setCurrentMode('select') + // Fallthrough + case 'select': + if (selectedElements[0]) { + // if we only have one selected element + if (!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: + svgCanvas.setCurProperties('fill', selected.getAttribute('fill')) + svgCanvas.setCurProperties('fill_opacity', selected.getAttribute('fill-opacity')) + svgCanvas.setCurProperties('stroke', selected.getAttribute('stroke')) + svgCanvas.setCurProperties('stroke_opacity', selected.getAttribute('stroke-opacity')) + svgCanvas.setCurProperties('stroke_width', selected.getAttribute('stroke-width')) + svgCanvas.setCurProperties('stroke_dasharray', selected.getAttribute('stroke-dasharray')) + svgCanvas.setCurProperties('stroke_linejoin', selected.getAttribute('stroke-linejoin')) + svgCanvas.setCurProperties('stroke_linecap', selected.getAttribute('stroke-linecap')) + } + + if (selected.tagName === 'text') { + svgCanvas.setCurText('font_size', selected.getAttribute('font-size')) + svgCanvas.setCurText('font_family', selected.getAttribute('font-family')) + } + svgCanvas.selectorManager.requestSelector(selected).showGrips(true) } + // always recalculate dimensions to strip off stray identity transforms + svgCanvas.recalculateAllSelectedDimensions() + // if it was being dragged/resized + if (realX !== svgCanvas.getRStartX() || realY !== svgCanvas.getRStartY()) { + const len = selectedElements.length + for (let i = 0; i < len; ++i) { + if (isNullish(selectedElements[i])) { break } + } // no change in position/size, so maybe we should move to pathedit - } else { - t = evt.target; - if (selectedElements[0].nodeName === 'path' && isNullish(selectedElements[1])) { - svgCanvas.pathActions.select(selectedElements[0]); + } else { + t = evt.target + if (selectedElements[0].nodeName === 'path' && isNullish(selectedElements[1])) { + svgCanvas.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 && tempJustSelected !== t) { - svgCanvas.removeFromSelection([ t ]); + } else if (evt.shiftKey && tempJustSelected !== t) { + svgCanvas.removeFromSelection([t]) + } + } // no change in mouse position + + // Remove non-scaling stroke + const elem = selectedElements[0] + if (elem) { + elem.removeAttribute('style') + walkTree(elem, (el) => { + el.removeAttribute('style') + }) } - } // no change in mouse position - - // Remove non-scaling stroke - const elem = selectedElements[0]; - if (elem) { - elem.removeAttribute('style'); - walkTree(elem, (el) => { - el.removeAttribute('style'); - }); } - - } - return; - case 'zoom': { - if (!isNullish(svgCanvas.getRubberBox())) { - svgCanvas.getRubberBox().setAttribute('display', 'none'); - } - const factor = evt.shiftKey ? 0.5 : 2; - svgCanvas.call('zoomed', { - x: Math.min(svgCanvas.getRStartX(), realX), - y: Math.min(svgCanvas.getRStartY(), realY), - width: Math.abs(realX - svgCanvas.getRStartX()), - height: Math.abs(realY - svgCanvas.getRStartY()), - factor - }); - return; - } case 'fhpath': { + return + case 'zoom': { + if (!isNullish(svgCanvas.getRubberBox())) { + svgCanvas.getRubberBox().setAttribute('display', 'none') + } + const factor = evt.shiftKey ? 0.5 : 2 + svgCanvas.call('zoomed', { + x: Math.min(svgCanvas.getRStartX(), realX), + y: Math.min(svgCanvas.getRStartY(), realY), + width: Math.abs(realX - svgCanvas.getRStartX()), + height: Math.abs(realY - svgCanvas.getRStartY()), + 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 - svgCanvas.setSumDistance(0); - svgCanvas.setControllPoint2('x', 0); - svgCanvas.setControllPoint2('y', 0); - svgCanvas.setControllPoint1('x', 0); - svgCanvas.setControllPoint1('y', 0); - svgCanvas.setStart({ x: 0, y: 0 }); - svgCanvas.setEnd('x', 0); - svgCanvas.setEnd('y', 0); - const coords = element.getAttribute('points'); - const commaIndex = coords.indexOf(','); - keep = commaIndex >= 0 ? coords.includes(',', commaIndex + 1) : coords.includes(' ', coords.indexOf(' ') + 1); - if (keep) { - element = svgCanvas.pathActions.smoothPolylineIntoPath(element); + svgCanvas.setSumDistance(0) + svgCanvas.setControllPoint2('x', 0) + svgCanvas.setControllPoint2('y', 0) + svgCanvas.setControllPoint1('x', 0) + svgCanvas.setControllPoint1('y', 0) + svgCanvas.setStart({ x: 0, y: 0 }) + svgCanvas.setEnd('x', 0) + svgCanvas.setEnd('y', 0) + const coords = element.getAttribute('points') + const commaIndex = coords.indexOf(',') + keep = commaIndex >= 0 ? coords.includes(',', commaIndex + 1) : coords.includes(' ', coords.indexOf(' ') + 1) + if (keep) { + element = svgCanvas.pathActions.smoothPolylineIntoPath(element) + } + break + } case 'line': { + const x1 = element.getAttribute('x1') + const y1 = element.getAttribute('y1') + const x2 = element.getAttribute('x2') + const y2 = element.getAttribute('y2') + keep = (x1 !== x2 || y1 !== y2) } - break; - } case 'line': { - const x1 = element.getAttribute('x1'); - const y1 = element.getAttribute('y1'); - const x2 = element.getAttribute('x2'); - const y2 = element.getAttribute('y2'); - keep = (x1 !== x2 || y1 !== y2); - } - break; - case 'foreignObject': - case 'square': - case 'rect': - case 'image': { - const width = element.getAttribute('width'); - const height = element.getAttribute('height'); - // Image should be kept regardless of size (use inherit dimensions later) - keep = (width || height) || svgCanvas.getCurrentMode() === 'image'; - } - break; - case 'circle': - keep = (element.getAttribute('r') !== '0'); - break; - case 'ellipse': { - const rx = Number(element.getAttribute('rx')); - const ry = Number(element.getAttribute('ry')); - keep = (rx || ry); - } - break; - case 'fhellipse': - if ((svgCanvas.getFreehand('maxx') - svgCanvas.getFreehand('minx')) > 0 && + break + case 'foreignObject': + case 'square': + case 'rect': + case 'image': { + const width = element.getAttribute('width') + const height = element.getAttribute('height') + // Image should be kept regardless of size (use inherit dimensions later) + keep = (width || height) || svgCanvas.getCurrentMode() === 'image' + } + break + case 'circle': + keep = (element.getAttribute('r') !== '0') + break + case 'ellipse': { + const rx = Number(element.getAttribute('rx')) + const ry = Number(element.getAttribute('ry')) + keep = (rx || ry) + } + break + case 'fhellipse': + if ((svgCanvas.getFreehand('maxx') - svgCanvas.getFreehand('minx')) > 0 && (svgCanvas.getFreehand('maxy') - svgCanvas.getFreehand('miny')) > 0) { - element = svgCanvas.addSVGElemensFromJson({ - element: 'ellipse', - curStyles: true, - attr: { - cx: (svgCanvas.getFreehand('minx') + svgCanvas.getFreehand('maxx')) / 2, - cy: (svgCanvas.getFreehand('miny') + svgCanvas.getFreehand('maxy')) / 2, - rx: (svgCanvas.getFreehand('maxx') - svgCanvas.getFreehand('minx')) / 2, - ry: (svgCanvas.getFreehand('maxy') - svgCanvas.getFreehand('miny')) / 2, - id: svgCanvas.getId() - } - }); - svgCanvas.call('changed', [ element ]); - keep = true; - } - break; - case 'fhrect': - if ((svgCanvas.getFreehand('maxx') - svgCanvas.getFreehand('minx')) > 0 && + element = svgCanvas.addSVGElemensFromJson({ + element: 'ellipse', + curStyles: true, + attr: { + cx: (svgCanvas.getFreehand('minx') + svgCanvas.getFreehand('maxx')) / 2, + cy: (svgCanvas.getFreehand('miny') + svgCanvas.getFreehand('maxy')) / 2, + rx: (svgCanvas.getFreehand('maxx') - svgCanvas.getFreehand('minx')) / 2, + ry: (svgCanvas.getFreehand('maxy') - svgCanvas.getFreehand('miny')) / 2, + id: svgCanvas.getId() + } + }) + svgCanvas.call('changed', [element]) + keep = true + } + break + case 'fhrect': + if ((svgCanvas.getFreehand('maxx') - svgCanvas.getFreehand('minx')) > 0 && (svgCanvas.getFreehand('maxy') - svgCanvas.getFreehand('miny')) > 0) { - element = svgCanvas.addSVGElemensFromJson({ - element: 'rect', - curStyles: true, - attr: { - x: svgCanvas.getFreehand('minx'), - y: svgCanvas.getFreehand('miny'), - width: (svgCanvas.getFreehand('maxx') - svgCanvas.getFreehand('minx')), - height: (svgCanvas.getFreehand('maxy') - svgCanvas.getFreehand('miny')), - id: svgCanvas.getId() - } - }); - svgCanvas.call('changed', [ element ]); - keep = true; - } - break; - case 'text': - keep = true; - svgCanvas.selectOnly([ element ]); - svgCanvas.textActions.start(element); - break; - case 'path': { + element = svgCanvas.addSVGElemensFromJson({ + element: 'rect', + curStyles: true, + attr: { + x: svgCanvas.getFreehand('minx'), + y: svgCanvas.getFreehand('miny'), + width: (svgCanvas.getFreehand('maxx') - svgCanvas.getFreehand('minx')), + height: (svgCanvas.getFreehand('maxy') - svgCanvas.getFreehand('miny')), + id: svgCanvas.getId() + } + }) + svgCanvas.call('changed', [element]) + keep = true + } + break + case 'text': + keep = true + svgCanvas.selectOnly([element]) + svgCanvas.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 - svgCanvas.setStarted(true); + element = null + // continue to be set to true so that mouseMove happens + svgCanvas.setStarted(true) - const res = svgCanvas.pathActions.mouseUp(evt, element, mouseX, mouseY); - ({ element } = res); - ({ keep } = res); - break; - } case 'pathedit': - keep = true; - element = null; - svgCanvas.pathActions.mouseUp(evt); - break; - case 'textedit': - keep = false; - element = null; - svgCanvas.textActions.mouseUp(evt, mouseX, mouseY); - break; - case 'rotate': { - keep = true; - element = null; - svgCanvas.setCurrentMode('select'); - const batchCmd = svgCanvas.undoMgr.finishUndoableChange(); - if (!batchCmd.isEmpty()) { - svgCanvas.addCommandToHistory(batchCmd); - } - // perform recalculation to weed out any stray identity transforms that might get stuck - svgCanvas.recalculateAllSelectedDimensions(); - svgCanvas.call('changed', selectedElements); - break; - } default: + const res = svgCanvas.pathActions.mouseUp(evt, element, mouseX, mouseY); + ({ element } = res); + ({ keep } = res) + break + } case 'pathedit': + keep = true + element = null + svgCanvas.pathActions.mouseUp(evt) + break + case 'textedit': + keep = false + element = null + svgCanvas.textActions.mouseUp(evt, mouseX, mouseY) + break + case 'rotate': { + keep = true + element = null + svgCanvas.setCurrentMode('select') + const batchCmd = svgCanvas.undoMgr.finishUndoableChange() + if (!batchCmd.isEmpty()) { + svgCanvas.addCommandToHistory(batchCmd) + } + // perform recalculation to weed out any stray identity transforms that might get stuck + svgCanvas.recalculateAllSelectedDimensions() + svgCanvas.call('changed', selectedElements) + break + } default: // This could occur in an extension - break; + break } /** @@ -785,28 +784,28 @@ export const mouseUpEvent = (evt) => { event: evt, mouse_x: mouseX, mouse_y: mouseY - }, true); + }, true) - extResult.forEach(function(r){ + extResult.forEach(function (r) { if (r) { keep = r.keep || keep; - ({ element } = r); - svgCanvas.setStarted(r.started || svgCanvas.getStarted()); + ({ element } = r) + svgCanvas.setStarted(r.started || svgCanvas.getStarted()) } - }); + }) if (!keep && !isNullish(element)) { - svgCanvas.getCurrentDrawing().releaseId(svgCanvas.getId()); - element.remove(); - element = null; + svgCanvas.getCurrentDrawing().releaseId(svgCanvas.getId()) + element.remove() + element = null - t = evt.target; + 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 elements while (t?.parentNode?.parentNode?.tagName === 'g') { - t = t.parentNode; + 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. @@ -817,88 +816,88 @@ export const mouseUpEvent = (evt) => { t.id !== 'svgcanvas' && t.id !== 'svgroot' ) { // switch into "select" mode if we've clicked on an element - svgCanvas.setMode('select'); - svgCanvas.selectOnly([ t ], true); + svgCanvas.setMode('select') + svgCanvas.selectOnly([t], true) } } else if (!isNullish(element)) { /** * @name module:svgcanvas.SvgCanvas#addedNew * @type {boolean} */ - svgCanvas.addedNew = true; + svgCanvas.addedNew = true - if (useUnit) { convertAttrs(element); } + if (useUnit) { convertAttrs(element) } - let aniDur = 0.2; - let cAni; - const curShape = svgCanvas.getStyle(); - const opacAni = svgCanvas.getOpacAni(); + let aniDur = 0.2 + let cAni + const curShape = svgCanvas.getStyle() + const opacAni = svgCanvas.getOpacAni() if (opacAni.beginElement && Number.parseFloat(element.getAttribute('opacity')) !== curShape.opacity) { - cAni = opacAni.cloneNode(true); - cAni.setAttribute('to', curShape.opacity); - cAni.setAttribute('dur', aniDur); - element.appendChild(cAni); + cAni = opacAni.cloneNode(true) + cAni.setAttribute('to', curShape.opacity) + cAni.setAttribute('dur', aniDur) + element.appendChild(cAni) try { // Fails in FF4 on foreignObject - cAni.beginElement(); - } catch (e) {/* empty fn */ } + cAni.beginElement() + } catch (e) { /* empty fn */ } } else { - aniDur = 0; + 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 (cAni) { cAni.remove() } + element.setAttribute('opacity', curShape.opacity) + element.setAttribute('style', 'pointer-events:inherit') + cleanupElement(element) if (svgCanvas.getCurrentMode() === 'path') { - svgCanvas.pathActions.toEditMode(element); + svgCanvas.pathActions.toEditMode(element) } else if (svgCanvas.getCurConfig().selectNew) { - const modes = [ 'circle', 'ellipse', 'square', 'rect', 'fhpath', 'line', 'fhellipse', 'fhrect', 'star', 'polygon' ]; - if ( modes.indexOf(svgCanvas.getCurrentMode()) !== -1) { - svgCanvas.setMode('select'); + const modes = ['circle', 'ellipse', 'square', 'rect', 'fhpath', 'line', 'fhellipse', 'fhrect', 'star', 'polygon'] + if (modes.indexOf(svgCanvas.getCurrentMode()) !== -1) { + svgCanvas.setMode('select') } - svgCanvas.selectOnly([ element ], true); + svgCanvas.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() - svgCanvas.addCommandToHistory(new InsertElementCommand(element)); - svgCanvas.call('changed', [ element ]); - }, aniDur * 1000); + svgCanvas.addCommandToHistory(new InsertElementCommand(element)) + svgCanvas.call('changed', [element]) + }, aniDur * 1000) } - svgCanvas.setStartTransform(null); -}; + svgCanvas.setStartTransform(null) +} export const dblClickEvent = (evt) => { - const selectedElements = svgCanvas.getSelectedElements(); - const evtTarget = evt.target; - const parent = evtTarget.parentNode; + const selectedElements = svgCanvas.getSelectedElements() + const evtTarget = evt.target + const parent = evtTarget.parentNode - let mouseTarget = svgCanvas.getMouseTarget(evt); - const { tagName } = mouseTarget; + let mouseTarget = svgCanvas.getMouseTarget(evt) + const { tagName } = mouseTarget if (tagName === 'text' && svgCanvas.getCurrentMode() !== 'textedit') { - const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()); - svgCanvas.textActions.select(mouseTarget, pt.x, pt.y); + const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()) + svgCanvas.textActions.select(mouseTarget, pt.x, pt.y) } // Do nothing if already in current group - if (parent === svgCanvas.getCurrentGroup()) { return; } + if (parent === svgCanvas.getCurrentGroup()) { 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 - svgCanvas.pushGroupProperties(mouseTarget); - mouseTarget = selectedElements[0]; - svgCanvas.clearSelection(true); + svgCanvas.pushGroupProperties(mouseTarget) + mouseTarget = selectedElements[0] + svgCanvas.clearSelection(true) } // Reset context if (svgCanvas.getCurrentGroup()) { - draw.leaveContext(); + draw.leaveContext() } if ((parent.tagName !== 'g' && parent.tagName !== 'a') || @@ -906,10 +905,10 @@ export const dblClickEvent = (evt) => { mouseTarget === svgCanvas.selectorManager.selectorParentGroup ) { // Escape from in-group edit - return; + return } - draw.setContext(mouseTarget); -}; + draw.setContext(mouseTarget) +} /** * Follows these conditions: @@ -922,337 +921,337 @@ export const dblClickEvent = (evt) => { * @returns {void} */ export const mouseDownEvent = (evt) => { - const dataStorage = svgCanvas.getDataStorage(); - const selectedElements = svgCanvas.getSelectedElements(); - const zoom = svgCanvas.getZoom(); - const curShape = svgCanvas.getStyle(); - const svgRoot = svgCanvas.getSvgRoot(); - const { $id } = svgCanvas; + const dataStorage = svgCanvas.getDataStorage() + const selectedElements = svgCanvas.getSelectedElements() + const zoom = svgCanvas.getZoom() + const curShape = svgCanvas.getStyle() + const svgRoot = svgCanvas.getSvgRoot() + const { $id } = svgCanvas - if (svgCanvas.spaceKey || evt.button === 1) { return; } + if (svgCanvas.spaceKey || evt.button === 1) { return } - const rightClick = (evt.button === 2); + const rightClick = (evt.button === 2) if (evt.altKey) { // duplicate when dragging - svgCanvas.cloneSelectedElements(0, 0); + svgCanvas.cloneSelectedElements(0, 0) } - svgCanvas.setRootSctm($id('svgcontent').querySelector('g').getScreenCTM().inverse()); + svgCanvas.setRootSctm($id('svgcontent').querySelector('g').getScreenCTM().inverse()) - const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()); - const mouseX = pt.x * zoom; - const mouseY = pt.y * zoom; + const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()) + const mouseX = pt.x * zoom + const mouseY = pt.y * zoom - evt.preventDefault(); + evt.preventDefault() if (rightClick) { - if(svgCanvas.getCurrentMode() === 'path'){ - return; + if (svgCanvas.getCurrentMode() === 'path') { + return } - svgCanvas.setCurrentMode('select'); - svgCanvas.setLastClickPoint(pt); + svgCanvas.setCurrentMode('select') + svgCanvas.setLastClickPoint(pt) } - let x = mouseX / zoom; - let y = mouseY / zoom; - let mouseTarget = svgCanvas.getMouseTarget(evt); + let x = mouseX / zoom + let y = mouseY / zoom + let mouseTarget = svgCanvas.getMouseTarget(evt) if (mouseTarget.tagName === 'a' && mouseTarget.childNodes.length === 1) { - mouseTarget = mouseTarget.firstChild; + mouseTarget = mouseTarget.firstChild } // realX/y ignores grid-snap value - const realX = x; - svgCanvas.setStartX(x); - svgCanvas.setRStartX(x); - const realY = y; - svgCanvas.setStartY(y); - svgCanvas.setRStartY(y); + const realX = x + svgCanvas.setStartX(x) + svgCanvas.setRStartX(x) + const realY = y + svgCanvas.setStartY(y) + svgCanvas.setRStartY(y) if (svgCanvas.getCurConfig().gridSnapping) { - x = snapToGrid(x); - y = snapToGrid(y); - svgCanvas.setStartX(snapToGrid(svgCanvas.getStartX())); - svgCanvas.setStartY(snapToGrid(svgCanvas.getStartY())); + x = snapToGrid(x) + y = snapToGrid(y) + svgCanvas.setStartX(snapToGrid(svgCanvas.getStartX())) + svgCanvas.setStartY(snapToGrid(svgCanvas.getStartY())) } // 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 === svgCanvas.selectorManager.selectorParentGroup && !isNullish(selectedElements[0])) { - const grip = evt.target; - const griptype = dataStorage.get(grip, 'type'); + const grip = evt.target + const griptype = dataStorage.get(grip, 'type') // rotating if (griptype === 'rotate') { - svgCanvas.setCurrentMode('rotate'); + svgCanvas.setCurrentMode('rotate') // svgCanvas.setCurrentRotateMode(dataStorage.get(grip, 'dir')); // resizing } else if (griptype === 'resize') { - svgCanvas.setCurrentMode('resize'); - svgCanvas.setCurrentResizeMode(dataStorage.get(grip, 'dir')); + svgCanvas.setCurrentMode('resize') + svgCanvas.setCurrentResizeMode(dataStorage.get(grip, 'dir')) } - mouseTarget = selectedElements[0]; + mouseTarget = selectedElements[0] } - svgCanvas.setStartTransform(mouseTarget.getAttribute('transform')); + svgCanvas.setStartTransform(mouseTarget.getAttribute('transform')) - const tlist = mouseTarget.transform.baseVal; + const tlist = mouseTarget.transform.baseVal switch (svgCanvas.getCurrentMode()) { - case 'select': - svgCanvas.setStarted(true); - svgCanvas.setCurrentResizeMode('none'); - if (rightClick) { svgCanvas.setStarted(false); } + case 'select': + svgCanvas.setStarted(true) + svgCanvas.setCurrentResizeMode('none') + if (rightClick) { svgCanvas.setStarted(false) } - if (mouseTarget !== svgRoot) { + if (mouseTarget !== svgRoot) { // if this element is not yet selected, clear selection and select it - if (!selectedElements.includes(mouseTarget)) { + if (!selectedElements.includes(mouseTarget)) { // only clear selection if shift is not pressed (otherwise, add // element to selection) - if (!evt.shiftKey) { + if (!evt.shiftKey) { // No need to do the call here as it will be done on addToSelection - svgCanvas.clearSelection(true); + svgCanvas.clearSelection(true) + } + svgCanvas.addToSelection([mouseTarget]) + svgCanvas.setJustSelected(mouseTarget) + svgCanvas.pathActions.clear() } - svgCanvas.addToSelection([ mouseTarget ]); - svgCanvas.setJustSelected(mouseTarget); - svgCanvas.pathActions.clear(); - } - // else if it's a path, go into pathedit mode in mouseup + // else if it's a path, go into pathedit mode in mouseup - if (!rightClick) { + 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; } - const slist = selectedElement.transform?.baseVal; - if (slist.numberOfItems) { - slist.insertItemBefore(svgRoot.createSVGTransform(), 0); - } else { - slist.appendItem(svgRoot.createSVGTransform()); + for (const selectedElement of selectedElements) { + if (isNullish(selectedElement)) { continue } + const slist = selectedElement.transform?.baseVal + if (slist.numberOfItems) { + slist.insertItemBefore(svgRoot.createSVGTransform(), 0) + } else { + slist.appendItem(svgRoot.createSVGTransform()) + } } } - } - } else if (!rightClick) { - svgCanvas.clearSelection(); - svgCanvas.setCurrentMode('multiselect'); - if (isNullish(svgCanvas.getRubberBox())) { - svgCanvas.setRubberBox(svgCanvas.selectorManager.getRubberBandBox()); - } - svgCanvas.setRStartX(svgCanvas.getRStartX() * zoom); - svgCanvas.setRStartY(svgCanvas.getRStartY() * zoom); + } else if (!rightClick) { + svgCanvas.clearSelection() + svgCanvas.setCurrentMode('multiselect') + if (isNullish(svgCanvas.getRubberBox())) { + svgCanvas.setRubberBox(svgCanvas.selectorManager.getRubberBandBox()) + } + svgCanvas.setRStartX(svgCanvas.getRStartX() * zoom) + svgCanvas.setRStartY(svgCanvas.getRStartY() * zoom) + assignAttributes(svgCanvas.getRubberBox(), { + x: svgCanvas.getRStartX(), + y: svgCanvas.getRStartY(), + width: 0, + height: 0, + display: 'inline' + }, 100) + } + break + case 'zoom': + svgCanvas.setStarted(true) + if (isNullish(svgCanvas.getRubberBox())) { + svgCanvas.setRubberBox(svgCanvas.selectorManager.getRubberBandBox()) + } assignAttributes(svgCanvas.getRubberBox(), { - x: svgCanvas.getRStartX(), - y: svgCanvas.getRStartY(), + x: realX * zoom, + y: realX * zoom, width: 0, height: 0, display: 'inline' - }, 100); - } - break; - case 'zoom': - svgCanvas.setStarted(true); - if (isNullish(svgCanvas.getRubberBox())) { - svgCanvas.setRubberBox(svgCanvas.selectorManager.getRubberBandBox()); - } - assignAttributes(svgCanvas.getRubberBox(), { - x: realX * zoom, - y: realX * zoom, - width: 0, - height: 0, - display: 'inline' - }, 100); - break; - case 'resize': { - svgCanvas.setStarted(true); - svgCanvas.setStartX(x); - svgCanvas.setStartY(y); + }, 100) + break + case 'resize': { + svgCanvas.setStarted(true) + svgCanvas.setStartX(x) + svgCanvas.setStartY(y) - // Getting the BBox from the selection box, since we know we - // want to orient around it - svgCanvas.setInitBbox(getBBox($id('selectedBox0'))); - const bb = {}; - for (const [ key, val ] of Object.entries(svgCanvas.getInitBbox())) { - bb[key] = val / zoom; - } - svgCanvas.setInitBbox(bb); - - // append three dummy transforms to the tlist so that - // we can translate,scale,translate in mousemove - const 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()); - } - break; - } - case 'fhellipse': - case 'fhrect': - case 'fhpath': - svgCanvas.setStart({ x: realX, y: realY }); - svgCanvas.setControllPoint1('x', 0); - svgCanvas.setControllPoint1('y', 0); - svgCanvas.setControllPoint2('x', 0); - svgCanvas.setControllPoint2('y', 0); - svgCanvas.setStarted(true); - svgCanvas.setDAttr(realX + ',' + realY + ' '); - // Commented out as doing nothing now: - // strokeW = parseFloat(curShape.stroke_width) === 0 ? 1 : curShape.stroke_width; - svgCanvas.addSVGElemensFromJson({ - element: 'polyline', - curStyles: true, - attr: { - points: svgCanvas.getDAttr(), - id: svgCanvas.getNextId(), - fill: 'none', - opacity: curShape.opacity / 2, - 'stroke-linecap': 'round', - style: 'pointer-events:none' + // Getting the BBox from the selection box, since we know we + // want to orient around it + svgCanvas.setInitBbox(getBBox($id('selectedBox0'))) + const bb = {} + for (const [key, val] of Object.entries(svgCanvas.getInitBbox())) { + bb[key] = val / zoom } - }); - svgCanvas.setFreehand('minx', realX); - svgCanvas.setFreehand('maxx', realX); - svgCanvas.setFreehand('miny', realY); - svgCanvas.setFreehand('maxy', realY); - break; - case 'image': { - svgCanvas.setStarted(true); - const newImage = svgCanvas.addSVGElemensFromJson({ - element: 'image', - attr: { - x, - y, - width: 0, - height: 0, - id: svgCanvas.getNextId(), - opacity: curShape.opacity / 2, - style: 'pointer-events:inherit' + svgCanvas.setInitBbox(bb) + + // append three dummy transforms to the tlist so that + // we can translate,scale,translate in mousemove + const 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()) } - }); - setHref(newImage, svgCanvas.getLastGoodImgUrl()); - preventClickDefault(newImage); - break; - } case 'square': + break + } + case 'fhellipse': + case 'fhrect': + case 'fhpath': + svgCanvas.setStart({ x: realX, y: realY }) + svgCanvas.setControllPoint1('x', 0) + svgCanvas.setControllPoint1('y', 0) + svgCanvas.setControllPoint2('x', 0) + svgCanvas.setControllPoint2('y', 0) + svgCanvas.setStarted(true) + svgCanvas.setDAttr(realX + ',' + realY + ' ') + // Commented out as doing nothing now: + // strokeW = parseFloat(curShape.stroke_width) === 0 ? 1 : curShape.stroke_width; + svgCanvas.addSVGElemensFromJson({ + element: 'polyline', + curStyles: true, + attr: { + points: svgCanvas.getDAttr(), + id: svgCanvas.getNextId(), + fill: 'none', + opacity: curShape.opacity / 2, + 'stroke-linecap': 'round', + style: 'pointer-events:none' + } + }) + svgCanvas.setFreehand('minx', realX) + svgCanvas.setFreehand('maxx', realX) + svgCanvas.setFreehand('miny', realY) + svgCanvas.setFreehand('maxy', realY) + break + case 'image': { + svgCanvas.setStarted(true) + const newImage = svgCanvas.addSVGElemensFromJson({ + element: 'image', + attr: { + x, + y, + width: 0, + height: 0, + id: svgCanvas.getNextId(), + opacity: curShape.opacity / 2, + style: 'pointer-events:inherit' + } + }) + setHref(newImage, svgCanvas.getLastGoodImgUrl()) + preventClickDefault(newImage) + break + } 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': - svgCanvas.setStarted(true); - svgCanvas.setStartX(x); - svgCanvas.setStartY(y); - svgCanvas.addSVGElemensFromJson({ - element: 'rect', - curStyles: true, - attr: { - x, - y, - width: 0, - height: 0, - id: svgCanvas.getNextId(), - opacity: curShape.opacity / 2 - } - }); - break; - case 'line': { - svgCanvas.setStarted(true); - const strokeW = Number(curShape.stroke_width) === 0 ? 1 : curShape.stroke_width; - svgCanvas.addSVGElemensFromJson({ - element: 'line', - curStyles: true, - attr: { - x1: x, - y1: y, - x2: x, - y2: y, - id: svgCanvas.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; - } case 'circle': - svgCanvas.setStarted(true); - svgCanvas.addSVGElemensFromJson({ - element: 'circle', - curStyles: true, - attr: { - cx: x, - cy: y, - r: 0, - id: svgCanvas.getNextId(), - opacity: curShape.opacity / 2 - } - }); - break; - case 'ellipse': - svgCanvas.setStarted(true); - svgCanvas.addSVGElemensFromJson({ - element: 'ellipse', - curStyles: true, - attr: { - cx: x, - cy: y, - rx: 0, - ry: 0, - id: svgCanvas.getNextId(), - opacity: curShape.opacity / 2 - } - }); - break; - case 'text': - svgCanvas.setStarted(true); - /* const newText = */ svgCanvas.addSVGElemensFromJson({ - element: 'text', - curStyles: true, - attr: { - x, - y, - id: svgCanvas.getNextId(), - fill: svgCanvas.getCurText('fill'), - 'stroke-width': svgCanvas.getCurText('stroke_width'), - 'font-size': svgCanvas.getCurText('font_size'), - 'font-family': svgCanvas.getCurText('font_family'), - 'text-anchor': 'middle', - 'xml:space': 'preserve', - opacity: curShape.opacity - } - }); - // newText.textContent = 'text'; - break; - case 'path': + case 'rect': + svgCanvas.setStarted(true) + svgCanvas.setStartX(x) + svgCanvas.setStartY(y) + svgCanvas.addSVGElemensFromJson({ + element: 'rect', + curStyles: true, + attr: { + x, + y, + width: 0, + height: 0, + id: svgCanvas.getNextId(), + opacity: curShape.opacity / 2 + } + }) + break + case 'line': { + svgCanvas.setStarted(true) + const strokeW = Number(curShape.stroke_width) === 0 ? 1 : curShape.stroke_width + svgCanvas.addSVGElemensFromJson({ + element: 'line', + curStyles: true, + attr: { + x1: x, + y1: y, + x2: x, + y2: y, + id: svgCanvas.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 + } case 'circle': + svgCanvas.setStarted(true) + svgCanvas.addSVGElemensFromJson({ + element: 'circle', + curStyles: true, + attr: { + cx: x, + cy: y, + r: 0, + id: svgCanvas.getNextId(), + opacity: curShape.opacity / 2 + } + }) + break + case 'ellipse': + svgCanvas.setStarted(true) + svgCanvas.addSVGElemensFromJson({ + element: 'ellipse', + curStyles: true, + attr: { + cx: x, + cy: y, + rx: 0, + ry: 0, + id: svgCanvas.getNextId(), + opacity: curShape.opacity / 2 + } + }) + break + case 'text': + svgCanvas.setStarted(true) + /* const newText = */ svgCanvas.addSVGElemensFromJson({ + element: 'text', + curStyles: true, + attr: { + x, + y, + id: svgCanvas.getNextId(), + fill: svgCanvas.getCurText('fill'), + 'stroke-width': svgCanvas.getCurText('stroke_width'), + 'font-size': svgCanvas.getCurText('font_size'), + 'font-family': svgCanvas.getCurText('font_family'), + 'text-anchor': 'middle', + 'xml:space': 'preserve', + opacity: curShape.opacity + } + }) + // newText.textContent = 'text'; + break + case 'path': // Fall through - case 'pathedit': - svgCanvas.setStartX(svgCanvas.getStartX() * zoom); - svgCanvas.setStartY(svgCanvas.getStartY() * zoom); - svgCanvas.pathActions.mouseDown(evt, mouseTarget, svgCanvas.getStartX(), svgCanvas.getStartY()); - svgCanvas.setStarted(true); - break; - case 'textedit': - svgCanvas.setStartX(svgCanvas.getStartX() * zoom); - svgCanvas.setStartY(svgCanvas.getStartY() * zoom); - svgCanvas.textActions.mouseDown(evt, mouseTarget, svgCanvas.getStartX(), svgCanvas.getStartY()); - svgCanvas.setStarted(true); - break; - case 'rotate': - svgCanvas.setStarted(true); - // we are starting an undoable change (a drag-rotation) - svgCanvas.undoMgr.beginUndoableChange('transform', selectedElements); - break; - default: + case 'pathedit': + svgCanvas.setStartX(svgCanvas.getStartX() * zoom) + svgCanvas.setStartY(svgCanvas.getStartY() * zoom) + svgCanvas.pathActions.mouseDown(evt, mouseTarget, svgCanvas.getStartX(), svgCanvas.getStartY()) + svgCanvas.setStarted(true) + break + case 'textedit': + svgCanvas.setStartX(svgCanvas.getStartX() * zoom) + svgCanvas.setStartY(svgCanvas.getStartY() * zoom) + svgCanvas.textActions.mouseDown(evt, mouseTarget, svgCanvas.getStartX(), svgCanvas.getStartY()) + svgCanvas.setStarted(true) + break + case 'rotate': + svgCanvas.setStarted(true) + // we are starting an undoable change (a drag-rotation) + svgCanvas.undoMgr.beginUndoableChange('transform', selectedElements) + break + default: // This could occur in an extension - break; + break } /** @@ -1269,14 +1268,14 @@ export const mouseDownEvent = (evt) => { start_x: svgCanvas.getStartX(), start_y: svgCanvas.getStartY(), selectedElements - }, true); + }, true) extResult.forEach((r) => { if (r && r.started) { - svgCanvas.setStarted(true); + svgCanvas.setStarted(true) } - }); -}; + }) +} /** * @param {Event} e * @fires module:event.SvgCanvas#event:updateCanvas @@ -1284,82 +1283,82 @@ export const mouseDownEvent = (evt) => { * @returns {void} */ export const DOMMouseScrollEvent = (e) => { - const zoom = svgCanvas.getZoom(); - const { $id } = svgCanvas; - if (!e.shiftKey) { return; } + const zoom = svgCanvas.getZoom() + const { $id } = svgCanvas + if (!e.shiftKey) { return } - e.preventDefault(); + e.preventDefault() - svgCanvas.setRootSctm($id('svgcontent').querySelector('g').getScreenCTM().inverse()); + svgCanvas.setRootSctm($id('svgcontent').querySelector('g').getScreenCTM().inverse()) - const workarea = document.getElementById('workarea'); - const scrbar = 15; - const rulerwidth = svgCanvas.getCurConfig().showRulers ? 16 : 0; + const workarea = document.getElementById('workarea') + const scrbar = 15 + const rulerwidth = svgCanvas.getCurConfig().showRulers ? 16 : 0 // mouse relative to content area in content pixels - const pt = transformPoint(e.clientX, e.clientY, svgCanvas.getrootSctm()); + const pt = transformPoint(e.clientX, e.clientY, svgCanvas.getrootSctm()) // full work area width in screen pixels - const editorFullW = parseFloat(getComputedStyle(workarea, null).width.replace("px", "")); - const editorFullH = parseFloat(getComputedStyle(workarea, null).height.replace("px", "")); + const editorFullW = parseFloat(getComputedStyle(workarea, null).width.replace('px', '')) + const editorFullH = parseFloat(getComputedStyle(workarea, null).height.replace('px', '')) // work area width minus scroll and ruler in screen pixels - const editorW = editorFullW - scrbar - rulerwidth; - const editorH = editorFullH - scrbar - rulerwidth; + const editorW = editorFullW - scrbar - rulerwidth + const editorH = editorFullH - scrbar - rulerwidth // work area width in content pixels - const workareaViewW = editorW * svgCanvas.getrootSctm().a; - const workareaViewH = editorH * svgCanvas.getrootSctm().d; + const workareaViewW = editorW * svgCanvas.getrootSctm().a + const workareaViewH = editorH * svgCanvas.getrootSctm().d // content offset from canvas in screen pixels - const wOffset = findPos(workarea); - const wOffsetLeft = wOffset.left + rulerwidth; - const wOffsetTop = wOffset.top + rulerwidth; + const wOffset = findPos(workarea) + const wOffsetLeft = wOffset.left + rulerwidth + const wOffsetTop = wOffset.top + rulerwidth - const delta = (e.wheelDelta) ? e.wheelDelta : (e.detail) ? - e.detail : 0; - if (!delta) { return; } + const delta = (e.wheelDelta) ? e.wheelDelta : (e.detail) ? -e.detail : 0 + if (!delta) { return } - let factor = Math.max(3 / 4, Math.min(4 / 3, (delta))); + let factor = Math.max(3 / 4, Math.min(4 / 3, (delta))) - let wZoom; let hZoom; + let wZoom; let hZoom if (factor > 1) { - wZoom = Math.ceil(editorW / workareaViewW * factor * 100) / 100; - hZoom = Math.ceil(editorH / workareaViewH * factor * 100) / 100; + 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; + 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)); + let zoomlevel = Math.min(wZoom, hZoom) + zoomlevel = Math.min(10, Math.max(0.01, zoomlevel)) if (zoomlevel === zoom) { - return; + return } - factor = zoomlevel / zoom; + factor = zoomlevel / zoom // top left of workarea in content pixels before zoom - const topLeftOld = transformPoint(wOffsetLeft, wOffsetTop, svgCanvas.getrootSctm()); + const topLeftOld = transformPoint(wOffsetLeft, wOffsetTop, svgCanvas.getrootSctm()) // 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 - }; + } - svgCanvas.setZoom(zoomlevel); - document.getElementById('zoom').value = ((zoomlevel * 100).toFixed(1)); + svgCanvas.setZoom(zoomlevel) + document.getElementById('zoom').value = ((zoomlevel * 100).toFixed(1)) - svgCanvas.call('updateCanvas', { center: false, newCtr }); - svgCanvas.call('zoomDone'); -}; + svgCanvas.call('updateCanvas', { center: false, newCtr }) + svgCanvas.call('zoomDone') +} diff --git a/src/svgcanvas/history.js b/src/svgcanvas/history.js index 3ada9d9e..3d04a70b 100644 --- a/src/svgcanvas/history.js +++ b/src/svgcanvas/history.js @@ -6,7 +6,7 @@ * @copyright 2010 Jeff Schiller */ -import { getHref, setHref, getRotationAngle, isNullish, getBBox } from './utilities.js'; +import { getHref, setHref, getRotationAngle, isNullish, getBBox } from './utilities.js' /** * Group: Undo/Redo history management. @@ -16,7 +16,7 @@ export const HistoryEventTypes = { AFTER_APPLY: 'after_apply', BEFORE_UNAPPLY: 'before_unapply', AFTER_UNAPPLY: 'after_unapply' -}; +} /** * Base class for commands. @@ -26,17 +26,18 @@ export class Command { * @returns {string} */ getText () { - return this.text; + 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); + handler && handler.handleHistoryEvent(HistoryEventTypes.BEFORE_APPLY, this) + applyFunction(handler) + handler && handler.handleHistoryEvent(HistoryEventTypes.AFTER_APPLY, this) } /** @@ -45,9 +46,9 @@ export class Command { * @returns {void} */ unapply (handler, unapplyFunction) { - handler && handler.handleHistoryEvent(HistoryEventTypes.BEFORE_UNAPPLY, this); - unapplyFunction(); - handler && handler.handleHistoryEvent(HistoryEventTypes.AFTER_UNAPPLY, this); + handler && handler.handleHistoryEvent(HistoryEventTypes.BEFORE_UNAPPLY, this) + unapplyFunction() + handler && handler.handleHistoryEvent(HistoryEventTypes.AFTER_UNAPPLY, this) } /** @@ -55,14 +56,14 @@ export class Command { * This function needs to be surcharged if multiple elements are returned. */ elements () { - return [ this.elem ]; + return [this.elem] } /** * @returns {string} String with element associated with this command */ type () { - return this.constructor.name; + return this.constructor.name } } @@ -137,13 +138,13 @@ export class MoveElementCommand extends Command { * @param {string} [text] - An optional string visible to user related to this change */ 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; + 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 } /** @@ -154,8 +155,8 @@ export class MoveElementCommand extends Command { */ apply (handler) { super.apply(handler, () => { - this.elem = this.newParent.insertBefore(this.elem, this.newNextSibling); - }); + this.elem = this.newParent.insertBefore(this.elem, this.newNextSibling) + }) } /** @@ -166,8 +167,8 @@ export class MoveElementCommand extends Command { */ unapply (handler) { super.unapply(handler, () => { - this.elem = this.oldParent.insertBefore(this.elem, this.oldNextSibling); - }); + this.elem = this.oldParent.insertBefore(this.elem, this.oldNextSibling) + }) } } @@ -181,11 +182,11 @@ export class InsertElementCommand extends Command { * @param {string} text - An optional string visible to user related to this change */ constructor (elem, text) { - super(); - this.elem = elem; - this.text = text || ('Create ' + elem.tagName); - this.parent = elem.parentNode; - this.nextSibling = this.elem.nextSibling; + super() + this.elem = elem + this.text = text || ('Create ' + elem.tagName) + this.parent = elem.parentNode + this.nextSibling = this.elem.nextSibling } /** @@ -196,8 +197,8 @@ export class InsertElementCommand extends Command { */ apply (handler) { super.apply(handler, () => { - this.elem = this.parent.insertBefore(this.elem, this.nextSibling); - }); + this.elem = this.parent.insertBefore(this.elem, this.nextSibling) + }) } /** @@ -208,13 +209,12 @@ export class InsertElementCommand extends Command { */ unapply (handler) { super.unapply(handler, () => { - this.parent = this.elem.parentNode; - this.elem.remove(); - }); + this.parent = this.elem.parentNode + this.elem.remove() + }) } } - /** * History command for an element removed from the DOM. * @implements {module:history.HistoryCommand} @@ -227,11 +227,11 @@ export class RemoveElementCommand extends Command { * @param {string} [text] - An optional string visible to user related to this change */ constructor (elem, oldNextSibling, oldParent, text) { - super(); - this.elem = elem; - this.text = text || ('Delete ' + elem.tagName); - this.nextSibling = oldNextSibling; - this.parent = oldParent; + super() + this.elem = elem + this.text = text || ('Delete ' + elem.tagName) + this.nextSibling = oldNextSibling + this.parent = oldParent } /** @@ -242,9 +242,9 @@ export class RemoveElementCommand extends Command { */ apply (handler) { super.apply(handler, () => { - this.parent = this.elem.parentNode; - this.elem.remove(); - }); + this.parent = this.elem.parentNode + this.elem.remove() + }) } /** @@ -256,10 +256,10 @@ export class RemoveElementCommand extends Command { unapply (handler) { super.unapply(handler, () => { if (isNullish(this.nextSibling) && window.console) { - console.error('Reference element was lost'); + 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` - }); + this.parent.insertBefore(this.elem, this.nextSibling) // Don't use `before` or `prepend` as `this.nextSibling` may be `null` + }) } } @@ -282,18 +282,18 @@ export class ChangeElementCommand extends Command { * @param {string} text - An optional string visible to user related to this change */ constructor (elem, attrs, text) { - super(); - this.elem = elem; - this.text = text ? ('Change ' + elem.tagName + ' ' + text) : ('Change ' + elem.tagName); - this.newValues = {}; - this.oldValues = attrs; + super() + this.elem = elem + this.text = text ? ('Change ' + elem.tagName + ' ' + text) : ('Change ' + elem.tagName) + this.newValues = {} + this.oldValues = attrs for (const attr in attrs) { if (attr === '#text') { - this.newValues[attr] = (elem) ? elem.textContent : ''; + this.newValues[attr] = (elem) ? elem.textContent : '' } else if (attr === '#href') { - this.newValues[attr] = getHref(elem); + this.newValues[attr] = getHref(elem) } else { - this.newValues[attr] = elem.getAttribute(attr); + this.newValues[attr] = elem.getAttribute(attr) } } } @@ -306,40 +306,40 @@ export class ChangeElementCommand extends Command { */ apply (handler) { super.apply(handler, () => { - let bChangedTransform = false; - Object.entries(this.newValues).forEach(([ attr, value ]) => { + let bChangedTransform = false + Object.entries(this.newValues).forEach(([attr, value]) => { if (value) { if (attr === '#text') { - this.elem.textContent = value; + this.elem.textContent = value } else if (attr === '#href') { - setHref(this.elem, value); + setHref(this.elem, value) } else { - this.elem.setAttribute(attr, value); + this.elem.setAttribute(attr, value) } } else if (attr === '#text') { - this.elem.textContent = ''; + this.elem.textContent = '' } else { - this.elem.setAttribute(attr, ''); - this.elem.removeAttribute(attr); + this.elem.setAttribute(attr, '') + this.elem.removeAttribute(attr) } - if (attr === 'transform') { bChangedTransform = true; } - }); + if (attr === 'transform') { bChangedTransform = true } + }) // relocate rotational transform, if necessary if (!bChangedTransform) { - const angle = getRotationAngle(this.elem); + const angle = getRotationAngle(this.elem) if (angle) { - const bbox = getBBox(this.elem); - const cx = bbox.x + bbox.width / 2; - const cy = bbox.y + bbox.height / 2; - const rotate = [ 'rotate(', angle, ' ', cx, ',', cy, ')' ].join(''); + const bbox = getBBox(this.elem) + 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); + this.elem.setAttribute('transform', rotate) } } } - }); + }) } /** @@ -350,37 +350,37 @@ export class ChangeElementCommand extends Command { */ unapply (handler) { super.unapply(handler, () => { - let bChangedTransform = false; - Object.entries(this.oldValues).forEach(([ attr, value ]) => { + let bChangedTransform = false + Object.entries(this.oldValues).forEach(([attr, value]) => { if (value) { if (attr === '#text') { - this.elem.textContent = value; + this.elem.textContent = value } else if (attr === '#href') { - setHref(this.elem, value); + setHref(this.elem, value) } else { - this.elem.setAttribute(attr, value); + this.elem.setAttribute(attr, value) } } else if (attr === '#text') { - this.elem.textContent = ''; + this.elem.textContent = '' } else { - this.elem.removeAttribute(attr); + this.elem.removeAttribute(attr) } - if (attr === 'transform') { bChangedTransform = true; } - }); + if (attr === 'transform') { bChangedTransform = true } + }) // relocate rotational transform, if necessary if (!bChangedTransform) { - const angle = getRotationAngle(this.elem); + const angle = getRotationAngle(this.elem) if (angle) { - const bbox = getBBox(this.elem); - const cx = bbox.x + bbox.width / 2; - const cy = bbox.y + bbox.height / 2; - const rotate = [ 'rotate(', angle, ' ', cx, ',', cy, ')' ].join(''); + const bbox = getBBox(this.elem) + 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); + this.elem.setAttribute('transform', rotate) } } } - }); + }) } } @@ -397,9 +397,9 @@ export class BatchCommand extends Command { * @param {string} [text] - An optional string visible to user related to this change */ constructor (text) { - super(); - this.text = text || 'Batch Command'; - this.stack = []; + super() + this.text = text || 'Batch Command' + this.stack = [] } /** @@ -411,10 +411,10 @@ export class BatchCommand extends Command { apply (handler) { super.apply(handler, () => { this.stack.forEach((stackItem) => { - console.assert(stackItem, 'stack item should not be null'); - stackItem && stackItem.apply(handler); - }); - }); + console.assert(stackItem, 'stack item should not be null') + stackItem && stackItem.apply(handler) + }) + }) } /** @@ -426,10 +426,10 @@ export class BatchCommand extends Command { unapply (handler) { super.unapply(handler, () => { this.stack.reverse().forEach((stackItem) => { - console.assert(stackItem, 'stack item should not be null'); - stackItem && stackItem.unapply(handler); - }); - }); + console.assert(stackItem, 'stack item should not be null') + stackItem && stackItem.unapply(handler) + }) + }) } /** @@ -437,17 +437,17 @@ export class BatchCommand extends Command { * @returns {Element[]} All the elements we are changing */ elements () { - const elems = []; - let cmd = this.stack.length; + const elems = [] + let cmd = this.stack.length while (cmd--) { - if (!this.stack[cmd]) continue; - const thisElems = this.stack[cmd].elements(); - let elem = thisElems.length; + if (!this.stack[cmd]) continue + const thisElems = this.stack[cmd].elements() + let elem = thisElems.length while (elem--) { - if (!elems.includes(thisElems[elem])) { elems.push(thisElems[elem]); } + if (!elems.includes(thisElems[elem])) { elems.push(thisElems[elem]) } } } - return elems; + return elems } /** @@ -456,15 +456,15 @@ export class BatchCommand extends Command { * @returns {void} */ addSubCommand (cmd) { - console.assert(cmd !== null, 'cmd should not be null'); - this.stack.push(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; + return !this.stack.length } } @@ -476,14 +476,14 @@ export class UndoManager { * @param {module:history.HistoryEventHandler} historyEventHandler */ constructor (historyEventHandler) { - this.handler_ = historyEventHandler || null; - this.undoStackPointer = 0; - this.undoStack = []; + this.handler_ = historyEventHandler || null + this.undoStackPointer = 0 + this.undoStack = [] // this is the stack that stores the original values, the elements and // the attribute name for begin/finish - this.undoChangeStackPointer = -1; - this.undoableChangeStack = []; + this.undoChangeStackPointer = -1 + this.undoableChangeStack = [] } /** @@ -491,36 +491,36 @@ export class UndoManager { * @returns {void} */ resetUndoStack () { - this.undoStack = []; - this.undoStackPointer = 0; + this.undoStack = [] + this.undoStackPointer = 0 } /** * @returns {Integer} Current size of the undo history stack */ getUndoStackSize () { - return this.undoStackPointer; + return this.undoStackPointer } /** * @returns {Integer} Current size of the redo history stack */ getRedoStackSize () { - return this.undoStack.length - this.undoStackPointer; + 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() : ''; + 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() : ''; + return this.undoStackPointer < this.undoStack.length ? this.undoStack[this.undoStackPointer].getText() : '' } /** @@ -529,8 +529,8 @@ export class UndoManager { */ undo () { if (this.undoStackPointer > 0) { - const cmd = this.undoStack[--this.undoStackPointer]; - cmd.unapply(this.handler_); + const cmd = this.undoStack[--this.undoStackPointer] + cmd.unapply(this.handler_) } } @@ -540,8 +540,8 @@ export class UndoManager { */ redo () { if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) { - const cmd = this.undoStack[this.undoStackPointer++]; - cmd.apply(this.handler_); + const cmd = this.undoStack[this.undoStackPointer++] + cmd.apply(this.handler_) } } @@ -559,10 +559,10 @@ export class UndoManager { // 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 = this.undoStack.splice(0, this.undoStackPointer) } - this.undoStack.push(cmd); - this.undoStackPointer = this.undoStack.length; + this.undoStack.push(cmd) + this.undoStackPointer = this.undoStack.length } /** @@ -576,20 +576,20 @@ export class UndoManager { * @returns {void} */ beginUndoableChange (attrName, elems) { - const p = ++this.undoChangeStackPointer; - let i = elems.length; - const oldValues = new Array(i); const elements = new Array(i); + const p = ++this.undoChangeStackPointer + let i = elems.length + const oldValues = new Array(i); const elements = new Array(i) while (i--) { - const elem = elems[i]; - if (isNullish(elem)) { continue; } - elements[i] = elem; - oldValues[i] = elem.getAttribute(attrName); + const elem = elems[i] + if (isNullish(elem)) { continue } + elements[i] = elem + oldValues[i] = elem.getAttribute(attrName) } this.undoableChangeStack[p] = { attrName, oldValues, elements - }; + } } /** @@ -599,21 +599,21 @@ export class UndoManager { * @returns {BatchCommand} Batch command object with resulting changes */ finishUndoableChange () { - const p = this.undoChangeStackPointer--; - const changeset = this.undoableChangeStack[p]; - const { attrName } = changeset; - const batchCmd = new BatchCommand('Change ' + attrName); - let i = changeset.elements.length; + const p = this.undoChangeStackPointer-- + const changeset = this.undoableChangeStack[p] + const { attrName } = changeset + const batchCmd = new BatchCommand('Change ' + attrName) + let i = changeset.elements.length while (i--) { - const elem = changeset.elements[i]; - if (isNullish(elem)) { continue; } - const changes = {}; - changes[attrName] = changeset.oldValues[i]; + const elem = changeset.elements[i] + if (isNullish(elem)) { continue } + const changes = {} + changes[attrName] = changeset.oldValues[i] if (changes[attrName] !== elem.getAttribute(attrName)) { - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes, attrName)); + batchCmd.addSubCommand(new ChangeElementCommand(elem, changes, attrName)) } } - this.undoableChangeStack[p] = null; - return batchCmd; + this.undoableChangeStack[p] = null + return batchCmd } } diff --git a/src/svgcanvas/historyrecording.js b/src/svgcanvas/historyrecording.js index 5e9f92ab..e4d7c907 100644 --- a/src/svgcanvas/historyrecording.js +++ b/src/svgcanvas/historyrecording.js @@ -8,7 +8,7 @@ import { BatchCommand, MoveElementCommand, InsertElementCommand, RemoveElementCommand, ChangeElementCommand -} from './history.js'; +} from './history.js' /** * History recording service. @@ -49,9 +49,9 @@ class HistoryRecordingService { * See singleton: {@link module:history.HistoryRecordingService.HistoryRecordingService.NO_HISTORY} */ constructor (undoManager) { - this.undoManager_ = undoManager; - this.currentBatchCommand_ = null; - this.batchCommandStack_ = []; + this.undoManager_ = undoManager + this.currentBatchCommand_ = null + this.batchCommandStack_ = [] } /** @@ -62,10 +62,10 @@ class HistoryRecordingService { * @returns {module:history.HistoryRecordingService} */ startBatchCommand (text) { - if (!this.undoManager_) { return this; } - this.currentBatchCommand_ = new BatchCommand(text); - this.batchCommandStack_.push(this.currentBatchCommand_); - return this; + if (!this.undoManager_) { return this } + this.currentBatchCommand_ = new BatchCommand(text) + this.batchCommandStack_.push(this.currentBatchCommand_) + return this } /** @@ -73,15 +73,15 @@ class HistoryRecordingService { * @returns {module:history.HistoryRecordingService} */ endBatchCommand () { - if (!this.undoManager_) { return this; } + 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); + const batchCommand = this.currentBatchCommand_ + this.batchCommandStack_.pop() + const { length: len } = this.batchCommandStack_ + this.currentBatchCommand_ = len ? this.batchCommandStack_[len - 1] : null + this.addCommand_(batchCommand) } - return this; + return this } /** @@ -93,9 +93,9 @@ class HistoryRecordingService { * @returns {module:history.HistoryRecordingService} */ moveElement (elem, oldNextSibling, oldParent, text) { - if (!this.undoManager_) { return this; } - this.addCommand_(new MoveElementCommand(elem, oldNextSibling, oldParent, text)); - return this; + if (!this.undoManager_) { return this } + this.addCommand_(new MoveElementCommand(elem, oldNextSibling, oldParent, text)) + return this } /** @@ -105,9 +105,9 @@ class HistoryRecordingService { * @returns {module:history.HistoryRecordingService} */ insertElement (elem, text) { - if (!this.undoManager_) { return this; } - this.addCommand_(new InsertElementCommand(elem, text)); - return this; + if (!this.undoManager_) { return this } + this.addCommand_(new InsertElementCommand(elem, text)) + return this } /** @@ -119,9 +119,9 @@ class HistoryRecordingService { * @returns {module:history.HistoryRecordingService} */ removeElement (elem, oldNextSibling, oldParent, text) { - if (!this.undoManager_) { return this; } - this.addCommand_(new RemoveElementCommand(elem, oldNextSibling, oldParent, text)); - return this; + if (!this.undoManager_) { return this } + this.addCommand_(new RemoveElementCommand(elem, oldNextSibling, oldParent, text)) + return this } /** @@ -132,9 +132,9 @@ class HistoryRecordingService { * @returns {module:history.HistoryRecordingService} */ changeElement (elem, attrs, text) { - if (!this.undoManager_) { return this; } - this.addCommand_(new ChangeElementCommand(elem, attrs, text)); - return this; + if (!this.undoManager_) { return this } + this.addCommand_(new ChangeElementCommand(elem, attrs, text)) + return this } /** @@ -144,18 +144,18 @@ class HistoryRecordingService { * @returns {module:history.HistoryRecordingService|void} */ addCommand_ (cmd) { - if (!this.undoManager_) { return this; } + if (!this.undoManager_) { return this } if (this.currentBatchCommand_) { - this.currentBatchCommand_.addSubCommand(cmd); + this.currentBatchCommand_.addSubCommand(cmd) } else { - this.undoManager_.addCommandToHistory(cmd); + this.undoManager_.addCommandToHistory(cmd) } - return undefined; + 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. */ -HistoryRecordingService.NO_HISTORY = new HistoryRecordingService(); -export default HistoryRecordingService; +HistoryRecordingService.NO_HISTORY = new HistoryRecordingService() +export default HistoryRecordingService diff --git a/src/svgcanvas/jQuery.attr.js b/src/svgcanvas/jQuery.attr.js index f5178a82..2383dc92 100644 --- a/src/svgcanvas/jQuery.attr.js +++ b/src/svgcanvas/jQuery.attr.js @@ -19,8 +19,8 @@ * @returns {external:jQuery} */ export default function jQueryPluginSVG ($) { - const proxied = $.fn.attr; - const svgns = 'http://www.w3.org/2000/svg'; + const proxied = $.fn.attr + const svgns = 'http://www.w3.org/2000/svg' /** * @typedef {PlainObject} module:jQueryAttr.Attributes */ @@ -31,49 +31,49 @@ export default function jQueryPluginSVG ($) { * @returns {external:jQuery|module:jQueryAttr.Attributes} */ $.fn.attr = function (key, value) { - const len = this.length; - if (!len) { return proxied.call(this, key, value); } + const len = this.length + if (!len) { return proxied.call(this, key, value) } for (let i = 0; i < len; ++i) { - const elem = this[i]; + const elem = this[i] // set/get SVG attribute if (elem.namespaceURI === svgns) { // Setting attribute if (value !== undefined) { - elem.setAttribute(key, value); + elem.setAttribute(key, value) } else if (Array.isArray(key)) { // Getting attributes from array - const obj = {}; - let j = key.length; + const obj = {} + let j = key.length while (j--) { - const aname = key[j]; - let attr = elem.getAttribute(aname); + 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); + attr = isNaN(attr) ? attr : (attr - 0) } - obj[aname] = attr; + obj[aname] = attr } - return obj; + return obj } if (typeof key === 'object') { // Setting attributes from object - for (const [ name, val ] of Object.entries(key)) { - elem.setAttribute(name, val); + for (const [name, val] of Object.entries(key)) { + elem.setAttribute(name, val) } // Getting attribute } else { - let attr = elem.getAttribute(key); + let attr = elem.getAttribute(key) if (attr || attr === '0') { - attr = isNaN(attr) ? attr : (attr - 0); + attr = isNaN(attr) ? attr : (attr - 0) } - return attr; + return attr } } else { - return proxied.call(this, key, value); + return proxied.call(this, key, value) } } - return this; - }; - return $; + return this + } + return $ } diff --git a/src/svgcanvas/json.js b/src/svgcanvas/json.js index 5fea22ce..1ee92c67 100644 --- a/src/svgcanvas/json.js +++ b/src/svgcanvas/json.js @@ -5,11 +5,11 @@ * * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller */ -import { getElem, assignAttributes, cleanupElement } from './utilities.js'; -import { NS } from './namespaces.js'; +import { getElem, assignAttributes, cleanupElement } from './utilities.js' +import { NS } from './namespaces.js' -let svgCanvas = null; -let svgdoc_ = null; +let svgCanvas = null +let svgdoc_ = null /** * @function module:json.jsonContext#getSelectedElements @@ -26,9 +26,9 @@ let svgdoc_ = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; - svgdoc_ = canvas.getDOMDocument(); -}; + svgCanvas = canvas + svgdoc_ = canvas.getDOMDocument() +} /** * @function module:json.getJsonFromSvgElements Iterate element and return json format * @param {ArgumentsArray} data - element @@ -36,27 +36,27 @@ export const init = function (canvas) { */ export const getJsonFromSvgElements = (data) => { // Text node - if (data.nodeType === 3) return data.nodeValue; + 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; + retval.attr[attr.name] = attr.value } // Iterate children for (let i = 0, node; (node = data.childNodes[i]); i++) { - retval.children[i] = getJsonFromSvgElements(node); + retval.children[i] = getJsonFromSvgElements(node) } - return retval; -}; + return retval +} /** * This should really be an intersection implementing all rather than a union. @@ -65,23 +65,23 @@ export const getJsonFromSvgElements = (data) => { */ export const addSVGElementsFromJson = function (data) { - if (typeof data === 'string') return svgdoc_.createTextNode(data); + if (typeof data === 'string') return svgdoc_.createTextNode(data) - let shape = getElem(data.attr.id); + 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 = svgCanvas.getDrawing().getCurrentLayer(); + const currentLayer = svgCanvas.getDrawing().getCurrentLayer() if (shape && data.element !== shape.tagName) { - shape.remove(); - shape = null; + shape.remove() + shape = null } if (!shape) { - const ns = data.namespace || NS.SVG; - shape = svgdoc_.createElementNS(ns, data.element); + const ns = data.namespace || NS.SVG + shape = svgdoc_.createElementNS(ns, data.element) if (currentLayer) { - (svgCanvas.getCurrentGroup() || currentLayer).append(shape); + (svgCanvas.getCurrentGroup() || currentLayer).append(shape) } } - const curShape = svgCanvas.getCurShape(); + const curShape = svgCanvas.getCurShape() if (data.curStyles) { assignAttributes(shape, { fill: curShape.fill, @@ -94,17 +94,17 @@ export const addSVGElementsFromJson = function (data) { 'fill-opacity': curShape.fill_opacity, opacity: curShape.opacity / 2, style: 'pointer-events:inherit' - }, 100); + }, 100) } - assignAttributes(shape, data.attr, 100); - cleanupElement(shape); + assignAttributes(shape, data.attr, 100) + cleanupElement(shape) // Children if (data.children) { data.children.forEach((child) => { - shape.append(addSVGElementsFromJson(child)); - }); + shape.append(addSVGElementsFromJson(child)) + }) } - return shape; -}; + return shape +} diff --git a/src/svgcanvas/layer.js b/src/svgcanvas/layer.js index 1dfb3777..f49d1446 100644 --- a/src/svgcanvas/layer.js +++ b/src/svgcanvas/layer.js @@ -6,9 +6,8 @@ * @copyright 2011 Jeff Schiller, 2016 Flint O'Brien */ -import { NS } from './namespaces.js'; -import { toXml, walkTree, isNullish } from './utilities.js'; - +import { NS } from './namespaces.js' +import { toXml, walkTree, isNullish } from './utilities.js' /** * This class encapsulates the concept of a layer in the drawing. It can be constructed with @@ -31,29 +30,29 @@ class Layer { * a new layer to the document. */ constructor (name, group, svgElem) { - this.name_ = name; - this.group_ = svgElem ? null : group; + this.name_ = name + this.group_ = svgElem ? null : group if (svgElem) { // Create a group element with title and add it to the DOM. - const svgdoc = svgElem.ownerDocument; - this.group_ = svgdoc.createElementNS(NS.SVG, 'g'); - const layerTitle = svgdoc.createElementNS(NS.SVG, 'title'); - layerTitle.textContent = name; - this.group_.append(layerTitle); + const svgdoc = svgElem.ownerDocument + this.group_ = svgdoc.createElementNS(NS.SVG, 'g') + const layerTitle = svgdoc.createElementNS(NS.SVG, 'title') + layerTitle.textContent = name + this.group_.append(layerTitle) if (group) { - group.insertAdjacentElement('afterend', this.group_); + group.insertAdjacentElement('afterend', this.group_) } else { - svgElem.append(this.group_); + svgElem.append(this.group_) } } - addLayerClass(this.group_); + addLayerClass(this.group_) walkTree(this.group_, function (e) { - e.setAttribute('style', 'pointer-events:inherit'); - }); + e.setAttribute('style', 'pointer-events:inherit') + }) - this.group_.setAttribute('style', svgElem ? 'pointer-events:all' : 'pointer-events:none'); + this.group_.setAttribute('style', svgElem ? 'pointer-events:all' : 'pointer-events:none') } /** @@ -61,7 +60,7 @@ class Layer { * @returns {string} The layer name */ getName () { - return this.name_; + return this.name_ } /** @@ -69,7 +68,7 @@ class Layer { * @returns {SVGGElement} The layer SVG group */ getGroup () { - return this.group_; + return this.group_ } /** @@ -77,7 +76,7 @@ class Layer { * @returns {void} */ activate () { - this.group_.setAttribute('style', 'pointer-events:all'); + this.group_.setAttribute('style', 'pointer-events:all') } /** @@ -85,7 +84,7 @@ class Layer { * @returns {void} */ deactivate () { - this.group_.setAttribute('style', 'pointer-events:none'); + this.group_.setAttribute('style', 'pointer-events:none') } /** @@ -94,10 +93,10 @@ class Layer { * @returns {void} */ setVisible (visible) { - const expected = visible === undefined || visible ? 'inline' : 'none'; - const oldDisplay = this.group_.getAttribute('display'); + const expected = visible === undefined || visible ? 'inline' : 'none' + const oldDisplay = this.group_.getAttribute('display') if (oldDisplay !== expected) { - this.group_.setAttribute('display', expected); + this.group_.setAttribute('display', expected) } } @@ -106,7 +105,7 @@ class Layer { * @returns {boolean} True if visible. */ isVisible () { - return this.group_.getAttribute('display') !== 'none'; + return this.group_.getAttribute('display') !== 'none' } /** @@ -114,11 +113,11 @@ class Layer { * @returns {Float} Opacity value. */ getOpacity () { - const opacity = this.group_.getAttribute('opacity'); + const opacity = this.group_.getAttribute('opacity') if (isNullish(opacity)) { - return 1; + return 1 } - return Number.parseFloat(opacity); + return Number.parseFloat(opacity) } /** @@ -129,7 +128,7 @@ class Layer { */ setOpacity (opacity) { if (typeof opacity === 'number' && opacity >= 0.0 && opacity <= 1.0) { - this.group_.setAttribute('opacity', opacity); + this.group_.setAttribute('opacity', opacity) } } @@ -140,7 +139,7 @@ class Layer { */ appendChildren (children) { for (const child of children) { - this.group_.append(child); + this.group_.append(child) } } @@ -148,14 +147,14 @@ class Layer { * @returns {SVGTitleElement|null} */ getTitleElement () { - const len = this.group_.childNodes.length; + const len = this.group_.childNodes.length for (let i = 0; i < len; ++i) { - const child = this.group_.childNodes.item(i); + const child = this.group_.childNodes.item(i) if (child && child.tagName === 'title') { - return child; + return child } } - return null; + return null } /** @@ -165,21 +164,20 @@ class Layer { * @returns {string|null} The new name if changed; otherwise, null. */ setName (name, hrService) { - const previousName = this.name_; - name = toXml(name); + const previousName = this.name_ + name = toXml(name) // now change the underlying title element contents - const title = this.getTitleElement(); + const title = this.getTitleElement() if (title) { - while(title.firstChild) - title.removeChild(title.firstChild); - title.textContent = name; - this.name_ = name; + while (title.firstChild) { title.removeChild(title.firstChild) } + title.textContent = name + this.name_ = name if (hrService) { - hrService.changeElement(title, { '#text': previousName }); + hrService.changeElement(title, { '#text': previousName }) } - return this.name_; + return this.name_ } - return null; + return null } /** @@ -187,29 +185,30 @@ class Layer { * @returns {SVGGElement} The layer SVG group that was just removed. */ removeGroup () { - const group = this.group_; - this.group_.remove(); - this.group_ = undefined; - return group; + const group = this.group_ + this.group_.remove() + this.group_ = undefined + return group } + /** * Test whether an element is a layer or not. * @param {SVGGElement} elem - The SVGGElement to test. * @returns {boolean} True if the element is a layer */ static isLayer (elem) { - return elem && elem.tagName === 'g' && Layer.CLASS_REGEX.test(elem.getAttribute('class')); + return elem && elem.tagName === 'g' && Layer.CLASS_REGEX.test(elem.getAttribute('class')) } } /** * @property {string} CLASS_NAME - class attribute assigned to all layer groups. */ -Layer.CLASS_NAME = 'layer'; +Layer.CLASS_NAME = 'layer' /** * @property {RegExp} CLASS_REGEX - Used to test presence of class Layer.CLASS_NAME */ -Layer.CLASS_REGEX = new RegExp('(\\s|^)' + Layer.CLASS_NAME + '(\\s|$)'); +Layer.CLASS_REGEX = new RegExp('(\\s|^)' + Layer.CLASS_NAME + '(\\s|$)') /** * Add class `Layer.CLASS_NAME` to the element (usually `class='layer'`). @@ -218,12 +217,12 @@ Layer.CLASS_REGEX = new RegExp('(\\s|^)' + Layer.CLASS_NAME + '(\\s|$)'); * @returns {void} */ function addLayerClass (elem) { - const classes = elem.getAttribute('class'); + const classes = elem.getAttribute('class') if (isNullish(classes) || !classes.length) { - elem.setAttribute('class', Layer.CLASS_NAME); + elem.setAttribute('class', Layer.CLASS_NAME) } else if (!Layer.CLASS_REGEX.test(classes)) { - elem.setAttribute('class', classes + ' ' + Layer.CLASS_NAME); + elem.setAttribute('class', classes + ' ' + Layer.CLASS_NAME) } } -export default Layer; +export default Layer diff --git a/src/svgcanvas/math.js b/src/svgcanvas/math.js index 63736732..080e33ae 100644 --- a/src/svgcanvas/math.js +++ b/src/svgcanvas/math.js @@ -19,13 +19,13 @@ * @property {Float} y */ -import { NS } from './namespaces.js'; +import { NS } from './namespaces.js' // Constants -const NEAR_ZERO = 1e-14; +const NEAR_ZERO = 1e-14 // Throw away SVGSVGElement used for creating matrices/transforms. -const svg = document.createElementNS(NS.SVG, 'svg'); +const svg = document.createElementNS(NS.SVG, 'svg') /** * A (hopefully) quicker function to transform a point by a matrix @@ -37,8 +37,8 @@ const svg = document.createElementNS(NS.SVG, 'svg'); * @returns {module:math.XYObject} An x, y object representing the transformed point */ export 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 }; -}; + 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 @@ -48,8 +48,8 @@ export const transformPoint = function (x, y, m) { * @returns {boolean} Indicates whether or not the matrix is 1,0,0,1,0,0 */ export const isIdentity = function (m) { - return (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0); -}; + return (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0) +} /** * This function tries to return a `SVGMatrix` that is the multiplication `m1 * m2`. @@ -60,18 +60,18 @@ export const isIdentity = function (m) { */ export const matrixMultiply = function (...args) { const m = args.reduceRight((prev, m1) => { - return m1.multiply(prev); - }); + 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; } + if (Math.abs(m.a) < NEAR_ZERO) { m.a = 0 } + if (Math.abs(m.b) < NEAR_ZERO) { m.b = 0 } + if (Math.abs(m.c) < NEAR_ZERO) { m.c = 0 } + if (Math.abs(m.d) < NEAR_ZERO) { m.d = 0 } + if (Math.abs(m.e) < NEAR_ZERO) { m.e = 0 } + if (Math.abs(m.f) < NEAR_ZERO) { m.f = 0 } - return m; -}; + return m +} /** * See if the given transformlist includes a non-indentity matrix transform. @@ -80,14 +80,14 @@ export const matrixMultiply = function (...args) { * @returns {boolean} Whether or not a matrix transform was found */ export const hasMatrixTransform = function (tlist) { - if (!tlist) { return false; } - let num = tlist.numberOfItems; + if (!tlist) { return false } + let num = tlist.numberOfItems while (num--) { - const xform = tlist.getItem(num); - if (xform.type === 1 && !isIdentity(xform.matrix)) { return true; } + const xform = tlist.getItem(num) + if (xform.type === 1 && !isIdentity(xform.matrix)) { return true } } - return false; -}; + return false +} /** * @typedef {PlainObject} module:math.TransformedBox An object with the following values @@ -113,15 +113,15 @@ export const hasMatrixTransform = function (tlist) { * @returns {module:math.TransformedBox} */ export const transformBox = function (l, t, w, h, m) { - const tl = transformPoint(l, t, m); - const tr = transformPoint((l + w), t, m); - const bl = transformPoint(l, (t + h), m); - const br = transformPoint((l + w), (t + h), m); + const tl = transformPoint(l, t, m) + const tr = transformPoint((l + w), t, m) + const bl = transformPoint(l, (t + h), m) + const br = transformPoint((l + w), (t + h), m) - const minx = Math.min(tl.x, tr.x, bl.x, br.x); - const maxx = Math.max(tl.x, tr.x, bl.x, br.x); - const miny = Math.min(tl.y, tr.y, bl.y, br.y); - const maxy = Math.max(tl.y, tr.y, bl.y, br.y); + const minx = Math.min(tl.x, tr.x, bl.x, br.x) + const maxx = Math.max(tl.x, tr.x, bl.x, br.x) + const miny = Math.min(tl.y, tr.y, bl.y, br.y) + const maxy = Math.max(tl.y, tr.y, bl.y, br.y) return { tl, @@ -134,8 +134,8 @@ export const transformBox = function (l, t, w, h, m) { width: (maxx - minx), height: (maxy - miny) } - }; -}; + } +} /** * This returns a single matrix Transform for a given Transform List @@ -152,23 +152,23 @@ export const transformBox = function (l, t, w, h, m) { export const transformListToTransform = function (tlist, min, max) { if (!tlist) { // Or should tlist = null have been prevented before this? - return svg.createSVGTransformFromMatrix(svg.createSVGMatrix()); + return svg.createSVGTransformFromMatrix(svg.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.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.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.createSVGMatrix()); - m = matrixMultiply(m, mtom); + : svg.createSVGMatrix()) + m = matrixMultiply(m, mtom) } - return svg.createSVGTransformFromMatrix(m); -}; + return svg.createSVGTransformFromMatrix(m) +} /** * Get the matrix object for a given element. @@ -177,9 +177,9 @@ export const transformListToTransform = function (tlist, min, max) { * @returns {SVGMatrix} The matrix object associated with the element's transformlist */ export const getMatrix = (elem) => { - const tlist = elem.transform.baseVal; - return transformListToTransform(tlist).matrix; -}; + const tlist = elem.transform.baseVal + return transformListToTransform(tlist).matrix +} /** * Returns a 45 degree angle coordinate associated with the two given @@ -192,19 +192,19 @@ export const getMatrix = (elem) => { * @returns {module:math.AngleCoord45} */ export const snapToAngle = (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; + 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. @@ -217,5 +217,5 @@ export const 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; -}; + (r2.y + r2.height) > r1.y +} diff --git a/src/svgcanvas/namespaces.js b/src/svgcanvas/namespaces.js index 3771691a..5dae4684 100644 --- a/src/svgcanvas/namespaces.js +++ b/src/svgcanvas/namespaces.js @@ -25,16 +25,16 @@ export const NS = { // OSB: 'http://www.openswatchbook.org/uri/2009/osb', // CC: 'http://creativecommons.org/ns#', // DC: 'http://purl.org/dc/elements/1.1/' -}; +} /** * @function module:namespaces.getReverseNS * @returns {string} The NS with key values switched and lowercase */ export const getReverseNS = function () { - const reverseNS = {}; - Object.entries(NS).forEach(([ name, URI ]) => { - reverseNS[URI] = name.toLowerCase(); - }); - return reverseNS; -}; + const reverseNS = {} + Object.entries(NS).forEach(([name, URI]) => { + reverseNS[URI] = name.toLowerCase() + }) + return reverseNS +} diff --git a/src/svgcanvas/paste-elem.js b/src/svgcanvas/paste-elem.js index b6725c0c..0af0f254 100644 --- a/src/svgcanvas/paste-elem.js +++ b/src/svgcanvas/paste-elem.js @@ -1,13 +1,13 @@ import { getStrokedBBoxDefaultVisible -} from './utilities.js'; -import * as hstry from './history.js'; +} from './utilities.js' +import * as hstry from './history.js' const { InsertElementCommand, BatchCommand -} = hstry; +} = hstry -let svgCanvas = null; +let svgCanvas = null /** * @function module:paste-elem.init @@ -15,8 +15,8 @@ let svgCanvas = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; -}; + svgCanvas = canvas +} /** * @function module:svgcanvas.SvgCanvas#pasteElements @@ -28,13 +28,13 @@ export const init = function (canvas) { * @returns {void} */ export const pasteElementsMethod = function (type, x, y) { - let clipb = JSON.parse(sessionStorage.getItem(svgCanvas.getClipboardID())); - if (!clipb) return; - let len = clipb.length; - if (!len) return; + let clipb = JSON.parse(sessionStorage.getItem(svgCanvas.getClipboardID())) + if (!clipb) return + let len = clipb.length + if (!len) return - const pasted = []; - const batchCmd = new BatchCommand('Paste elements'); + const pasted = [] + const batchCmd = new BatchCommand('Paste elements') // const drawing = getCurrentDrawing(); /** * @typedef {PlainObject} module:svgcanvas.ChangedIDs @@ -42,7 +42,7 @@ export const pasteElementsMethod = function (type, x, y) { /** * @type {module:svgcanvas.ChangedIDs} */ - const changedIDs = {}; + const changedIDs = {} // Recursively replace IDs and record the changes /** @@ -52,12 +52,12 @@ export const pasteElementsMethod = function (type, x, y) { */ function checkIDs (elem) { if (elem.attr && elem.attr.id) { - changedIDs[elem.attr.id] = svgCanvas.getNextId(); - elem.attr.id = changedIDs[elem.attr.id]; + changedIDs[elem.attr.id] = svgCanvas.getNextId() + elem.attr.id = changedIDs[elem.attr.id] } - if (elem.children) elem.children.forEach((child) => checkIDs(child)); + if (elem.children) elem.children.forEach((child) => checkIDs(child)) } - clipb.forEach((elem) => checkIDs(elem)); + clipb.forEach((elem) => checkIDs(elem)) // Give extensions like the connector extension a chance to reflect new IDs and remove invalid elements /** @@ -73,55 +73,55 @@ export const pasteElementsMethod = function (type, x, y) { { elems: clipb, changes: changedIDs }, true ).forEach(function (extChanges) { - if (!extChanges || !('remove' in extChanges)) return; + if (!extChanges || !('remove' in extChanges)) return extChanges.remove.forEach(function (removeID) { clipb = clipb.filter(function (clipBoardItem) { - return clipBoardItem.attr.id !== removeID; - }); - }); - }); + return clipBoardItem.attr.id !== removeID + }) + }) + }) // Move elements to lastClickPoint while (len--) { - const elem = clipb[len]; - if (!elem) { continue; } + const elem = clipb[len] + if (!elem) { continue } - const copy = svgCanvas.addSVGElemensFromJson(elem); - pasted.push(copy); - batchCmd.addSubCommand(new InsertElementCommand(copy)); + const copy = svgCanvas.addSVGElemensFromJson(elem) + pasted.push(copy) + batchCmd.addSubCommand(new InsertElementCommand(copy)) - svgCanvas.restoreRefElements(copy); + svgCanvas.restoreRefElements(copy) } - svgCanvas.selectOnly(pasted); + svgCanvas.selectOnly(pasted) if (type !== 'in_place') { - let ctrX; let ctrY; + let ctrX; let ctrY if (!type) { - ctrX = svgCanvas.getLastClickPoint('x'); - ctrY = svgCanvas.getLastClickPoint('y'); + ctrX = svgCanvas.getLastClickPoint('x') + ctrY = svgCanvas.getLastClickPoint('y') } else if (type === 'point') { - ctrX = x; - ctrY = y; + ctrX = x + ctrY = y } - const bbox = getStrokedBBoxDefaultVisible(pasted); - const cx = ctrX - (bbox.x + bbox.width / 2); - const cy = ctrY - (bbox.y + bbox.height / 2); - const dx = []; - const dy = []; + const bbox = getStrokedBBoxDefaultVisible(pasted) + const cx = ctrX - (bbox.x + bbox.width / 2) + const cy = ctrY - (bbox.y + bbox.height / 2) + const dx = [] + const dy = [] - pasted.forEach(function(_item){ - dx.push(cx); - dy.push(cy); - }); + pasted.forEach(function (_item) { + dx.push(cx) + dy.push(cy) + }) - const cmd = svgCanvas.moveSelectedElements(dx, dy, false); - if (cmd) batchCmd.addSubCommand(cmd); + const cmd = svgCanvas.moveSelectedElements(dx, dy, false) + if (cmd) batchCmd.addSubCommand(cmd) } - svgCanvas.addCommandToHistory(batchCmd); - svgCanvas.call('changed', pasted); -}; + svgCanvas.addCommandToHistory(batchCmd) + svgCanvas.call('changed', pasted) +} diff --git a/src/svgcanvas/path-actions.js b/src/svgcanvas/path-actions.js index daf911f7..882f13af 100644 --- a/src/svgcanvas/path-actions.js +++ b/src/svgcanvas/path-actions.js @@ -6,20 +6,20 @@ * @copyright 2011 Alexis Deveria, 2011 Jeff Schiller */ -import { NS } from './namespaces.js'; -import { shortFloat } from '../common/units.js'; -import { ChangeElementCommand, BatchCommand } from './history.js'; +import { NS } from './namespaces.js' +import { shortFloat } from '../common/units.js' +import { ChangeElementCommand, BatchCommand } from './history.js' import { transformPoint, snapToAngle, rectsIntersect, transformListToTransform -} from './math.js'; +} from './math.js' import { assignAttributes, getElem, getRotationAngle, snapToGrid, isNullish, getBBox -} from './utilities.js'; +} from './utilities.js' -let svgCanvas = null; -let path = null; +let svgCanvas = null +let path = null /** * @function module:path-actions.init @@ -27,8 +27,8 @@ let path = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; -}; + svgCanvas = canvas +} /** * Convert a path to one with only absolute or relative values. @@ -39,174 +39,174 @@ export const init = function (canvas) { * @returns {string} */ export const convertPath = function (pth, toRel) { - const { pathSegList } = pth; - const len = pathSegList.numberOfItems; - let curx = 0; let cury = 0; - let d = ''; - let lastM = null; + const { pathSegList } = pth + const len = pathSegList.numberOfItems + let curx = 0; let cury = 0 + let d = '' + let lastM = null for (let i = 0; i < len; ++i) { - const seg = pathSegList.getItem(i); + const seg = pathSegList.getItem(i) // if these properties are not in the segment, set them to zero - let x = seg.x || 0; - let y = seg.y || 0; - let x1 = seg.x1 || 0; - let y1 = seg.y1 || 0; - let x2 = seg.x2 || 0; - let y2 = seg.y2 || 0; + let x = seg.x || 0 + let y = seg.y || 0 + let x1 = seg.x1 || 0 + let y1 = seg.y1 || 0 + let x2 = seg.x2 || 0 + let y2 = seg.y2 || 0 // const type = seg.pathSegType; // const pathMap = svgCanvas.getPathMap(); // let letter = pathMap[type][toRel ? 'toLowerCase' : 'toUpperCase'](); - let letter = seg.pathSegTypeAsLetter; + let letter = seg.pathSegTypeAsLetter switch (letter) { - case 'z': // z,Z closepath (Z/z) - case 'Z': - d += 'z'; - if (lastM && !toRel) { - curx = lastM[0]; - cury = lastM[1]; - } - break; - case 'H': // absolute horizontal line (H) - x -= curx; + case 'z': // z,Z closepath (Z/z) + case 'Z': + d += 'z' + if (lastM && !toRel) { + curx = lastM[0] + cury = lastM[1] + } + break + case 'H': // absolute horizontal line (H) + x -= curx // Fallthrough - case 'h': // relative horizontal line (h) - if (toRel) { - y = 0; - curx += x; - letter = 'l'; - } else { - y = cury; - x += curx; - curx = x; - letter = 'L'; - } - // Convert to "line" for easier editing - d += pathDSegment(letter, [ [ x, y ] ]); - break; - case 'V': // absolute vertical line (V) - y -= cury; + case 'h': // relative horizontal line (h) + if (toRel) { + y = 0 + curx += x + letter = 'l' + } else { + y = cury + x += curx + curx = x + letter = 'L' + } + // Convert to "line" for easier editing + d += pathDSegment(letter, [[x, y]]) + break + case 'V': // absolute vertical line (V) + y -= cury // Fallthrough - case 'v': // relative vertical line (v) - if (toRel) { - x = 0; - cury += y; - letter = 'l'; - } else { - x = curx; - y += cury; - cury = y; - letter = 'L'; - } - // Convert to "line" for easier editing - d += pathDSegment(letter, [ [ x, y ] ]); - break; - case 'M': // absolute move (M) - case 'L': // absolute line (L) - case 'T': // absolute smooth quad (T) - x -= curx; - y -= cury; + case 'v': // relative vertical line (v) + if (toRel) { + x = 0 + cury += y + letter = 'l' + } else { + x = curx + y += cury + cury = y + letter = 'L' + } + // Convert to "line" for easier editing + d += pathDSegment(letter, [[x, y]]) + break + case 'M': // absolute move (M) + case 'L': // absolute line (L) + case 'T': // absolute smooth quad (T) + x -= curx + y -= cury // Fallthrough - case 'l': // relative line (l) - case 'm': // relative move (m) - case 't': // relative smooth quad (t) - if (toRel) { - curx += x; - cury += y; - letter = letter.toLowerCase(); - } else { - x += curx; - y += cury; - curx = x; - cury = y; - letter = letter.toUpperCase(); - } - if (letter === 'm' || letter === 'M') { lastM = [ curx, cury ]; } + case 'l': // relative line (l) + case 'm': // relative move (m) + case 't': // relative smooth quad (t) + if (toRel) { + curx += x + cury += y + letter = letter.toLowerCase() + } else { + x += curx + y += cury + curx = x + cury = y + letter = letter.toUpperCase() + } + if (letter === 'm' || letter === 'M') { lastM = [curx, cury] } - d += pathDSegment(letter, [ [ x, y ] ]); - break; - case 'C': // absolute cubic (C) - x -= curx; x1 -= curx; x2 -= curx; - y -= cury; y1 -= cury; y2 -= cury; + d += pathDSegment(letter, [[x, y]]) + break + case 'C': // absolute cubic (C) + x -= curx; x1 -= curx; x2 -= curx + y -= cury; y1 -= cury; y2 -= cury // Fallthrough - case 'c': // relative cubic (c) - if (toRel) { - curx += x; - cury += y; - letter = 'c'; - } else { - x += curx; x1 += curx; x2 += curx; - y += cury; y1 += cury; y2 += cury; - curx = x; - cury = y; - letter = 'C'; - } - d += pathDSegment(letter, [ [ x1, y1 ], [ x2, y2 ], [ x, y ] ]); - break; - case 'Q': // absolute quad (Q) - x -= curx; x1 -= curx; - y -= cury; y1 -= cury; + case 'c': // relative cubic (c) + if (toRel) { + curx += x + cury += y + letter = 'c' + } else { + x += curx; x1 += curx; x2 += curx + y += cury; y1 += cury; y2 += cury + curx = x + cury = y + letter = 'C' + } + d += pathDSegment(letter, [[x1, y1], [x2, y2], [x, y]]) + break + case 'Q': // absolute quad (Q) + x -= curx; x1 -= curx + y -= cury; y1 -= cury // Fallthrough - case 'q': // relative quad (q) - if (toRel) { - curx += x; - cury += y; - letter = 'q'; - } else { - x += curx; x1 += curx; - y += cury; y1 += cury; - curx = x; - cury = y; - letter = 'Q'; - } - d += pathDSegment(letter, [ [ x1, y1 ], [ x, y ] ]); - break; - case 'A': - x -= curx; - y -= cury; + case 'q': // relative quad (q) + if (toRel) { + curx += x + cury += y + letter = 'q' + } else { + x += curx; x1 += curx + y += cury; y1 += cury + curx = x + cury = y + letter = 'Q' + } + d += pathDSegment(letter, [[x1, y1], [x, y]]) + break + case 'A': + x -= curx + y -= cury // fallthrough - case 'a': // relative elliptical arc (a) - if (toRel) { - curx += x; - cury += y; - letter = 'a'; - } else { - x += curx; - y += cury; - curx = x; - cury = y; - letter = 'A'; - } - d += pathDSegment(letter, [ [ seg.r1, seg.r2 ] ], [ - seg.angle, - (seg.largeArcFlag ? 1 : 0), - (seg.sweepFlag ? 1 : 0) - ], [ x, y ]); - break; - case 'S': // absolute smooth cubic (S) - x -= curx; x2 -= curx; - y -= cury; y2 -= cury; + case 'a': // relative elliptical arc (a) + if (toRel) { + curx += x + cury += y + letter = 'a' + } else { + x += curx + y += cury + curx = x + cury = y + letter = 'A' + } + d += pathDSegment(letter, [[seg.r1, seg.r2]], [ + seg.angle, + (seg.largeArcFlag ? 1 : 0), + (seg.sweepFlag ? 1 : 0) + ], [x, y]) + break + case 'S': // absolute smooth cubic (S) + x -= curx; x2 -= curx + y -= cury; y2 -= cury // Fallthrough - case 's': // relative smooth cubic (s) - if (toRel) { - curx += x; - cury += y; - letter = 's'; - } else { - x += curx; x2 += curx; - y += cury; y2 += cury; - curx = x; - cury = y; - letter = 'S'; - } - d += pathDSegment(letter, [ [ x2, y2 ], [ x, y ] ]); - break; + case 's': // relative smooth cubic (s) + if (toRel) { + curx += x + cury += y + letter = 's' + } else { + x += curx; x2 += curx + y += cury; y2 += cury + curx = x + cury = y + letter = 'S' + } + d += pathDSegment(letter, [[x2, y2], [x, y]]) + break } // switch on path segment type } // for each segment - return d; -}; + return d +} /** * TODO: refactor callers in `convertPath` to use `getPathDFromSegments` instead of this function. @@ -218,17 +218,17 @@ export const convertPath = function (pth, toRel) { * @returns {string} */ function pathDSegment (letter, points, morePoints, lastPoint) { - points.forEach(function(pnt, i){ - points[i] = shortFloat(pnt); - }); - let segment = letter + points.join(' '); + points.forEach(function (pnt, i) { + points[i] = shortFloat(pnt) + }) + let segment = letter + points.join(' ') if (morePoints) { - segment += ' ' + morePoints.join(' '); + segment += ' ' + morePoints.join(' ') } if (lastPoint) { - segment += ' ' + shortFloat(lastPoint); + segment += ' ' + shortFloat(lastPoint) } - return segment; + return segment } /** @@ -238,11 +238,11 @@ function pathDSegment (letter, points, morePoints, lastPoint) { * @memberof module:path */ export const pathActionsMethod = (function () { - let subpath = false; - let newPoint; let firstCtrl; + let subpath = false + let newPoint; let firstCtrl - let currentPath = null; - let hasMoved = false; + let currentPath = null + let hasMoved = false // No `svgCanvas` yet but should be ok as is `null` by default // svgCanvas.setDrawnPath(null); @@ -255,9 +255,9 @@ export const pathActionsMethod = (function () { * @returns {Element} */ const smoothPolylineIntoPath = function (element) { - let i; - const { points } = element; - const N = points.numberOfItems; + 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 // @@ -272,40 +272,40 @@ export const pathActionsMethod = (function () { // - 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 - let curpos = points.getItem(0); let prevCtlPt = null; - let d = []; - d.push([ 'M', curpos.x, ',', curpos.y, ' C' ].join('')); + let curpos = points.getItem(0); let prevCtlPt = null + let d = [] + d.push(['M', curpos.x, ',', curpos.y, ' C'].join('')) for (i = 1; i <= (N - 4); i += 3) { - let ct1 = points.getItem(i); - const ct2 = points.getItem(i + 1); - const end = points.getItem(i + 2); + 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) { - const newpts = svgCanvas.smoothControlPoints(prevCtlPt, ct1, curpos); + const newpts = svgCanvas.smoothControlPoints(prevCtlPt, ct1, curpos) if (newpts && newpts.length === 2) { - const prevArr = d[d.length - 1].split(','); - prevArr[2] = newpts[0].x; - prevArr[3] = newpts[0].y; - d[d.length - 1] = prevArr.join(','); - ct1 = newpts[1]; + const prevArr = d[d.length - 1].split(',') + prevArr[2] = newpts[0].x + prevArr[3] = newpts[0].y + d[d.length - 1] = prevArr.join(',') + ct1 = newpts[1] } } - d.push([ ct1.x, ct1.y, ct2.x, ct2.y, end.x, end.y ].join(',')); + d.push([ct1.x, ct1.y, ct2.x, ct2.y, end.x, end.y].join(',')) - curpos = end; - prevCtlPt = ct2; + curpos = end + prevCtlPt = ct2 } // handle remaining line segments - d.push('L'); + d.push('L') while (i < N) { - const pt = points.getItem(i); - d.push([ pt.x, pt.y ].join(',')); - i++; + const pt = points.getItem(i) + d.push([pt.x, pt.y].join(',')) + i++ } - d = d.join(' '); + d = d.join(' ') element = svgCanvas.addSVGElemensFromJson({ element: 'path', @@ -315,11 +315,11 @@ export const pathActionsMethod = (function () { d, fill: 'none' } - }); + }) // No need to call "changed", as this is already done under mouseUp } - return element; - }; + return element + } return (/** @lends module:path.pathActions */ { /** @@ -330,42 +330,42 @@ export const pathActionsMethod = (function () { * @returns {boolean|void} */ mouseDown (evt, mouseTarget, startX, startY) { - let id; + let id if (svgCanvas.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) - let mouseY = startY; // Was this meant to work with the other `mouseY`? (was defined globally so adding `let` to at least avoid a global) + let mouseX = startX // Was this meant to work with the other `mouseX`? (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) - const zoom = svgCanvas.getZoom(); - let x = mouseX / zoom; - let y = mouseY / zoom; - let stretchy = getElem('path_stretch_line'); - newPoint = [ x, y ]; + const zoom = svgCanvas.getZoom() + let x = mouseX / zoom + let y = mouseY / zoom + let stretchy = getElem('path_stretch_line') + newPoint = [x, y] if (svgCanvas.getGridSnapping()) { - x = snapToGrid(x); - y = snapToGrid(y); - mouseX = snapToGrid(mouseX); - mouseY = snapToGrid(mouseY); + x = snapToGrid(x) + y = snapToGrid(y) + mouseX = snapToGrid(mouseX) + mouseY = snapToGrid(mouseY) } if (!stretchy) { - stretchy = document.createElementNS(NS.SVG, 'path'); + stretchy = document.createElementNS(NS.SVG, 'path') assignAttributes(stretchy, { id: 'path_stretch_line', stroke: '#22C', 'stroke-width': '0.5', fill: 'none' - }); - getElem('selectorParentGroup').append(stretchy); + }) + getElem('selectorParentGroup').append(stretchy) } - stretchy.setAttribute('display', 'inline'); + stretchy.setAttribute('display', 'inline') - let keep = null; - let index; + let keep = null + let index // if pts array is empty, create path element with M at current point - const drawnPath = svgCanvas.getDrawnPath(); + const drawnPath = svgCanvas.getDrawnPath() if (!drawnPath) { - 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) + 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 = */ svgCanvas.setDrawnPath(svgCanvas.addSVGElemensFromJson({ element: 'path', curStyles: true, @@ -374,40 +374,40 @@ export const pathActionsMethod = (function () { id: svgCanvas.getNextId(), opacity: svgCanvas.getOpacity() / 2 } - })); + })) // set stretchy line to first point - stretchy.setAttribute('d', [ 'M', mouseX, mouseY, mouseX, mouseY ].join(' ')); - index = subpath ? path.segs.length : 0; - svgCanvas.addPointGrip(index, mouseX, mouseY); + stretchy.setAttribute('d', ['M', mouseX, mouseY, mouseX, mouseY].join(' ')) + index = subpath ? path.segs.length : 0 + svgCanvas.addPointGrip(index, mouseX, mouseY) } else { // determine if we clicked on an existing point - const seglist = drawnPath.pathSegList; - let i = seglist.numberOfItems; - const FUZZ = 6 / zoom; - let clickOnPoint = false; + const seglist = drawnPath.pathSegList + let i = seglist.numberOfItems + const FUZZ = 6 / zoom + let clickOnPoint = false while (i) { - i--; - const item = seglist.getItem(i); - const px = item.x; const py = item.y; + i-- + const item = seglist.getItem(i) + const px = item.x; const py = item.y // found a matching point if (x >= (px - FUZZ) && x <= (px + FUZZ) && y >= (py - FUZZ) && y <= (py + FUZZ) ) { - clickOnPoint = true; - break; + clickOnPoint = true + break } } // get path element that we are in the process of creating - id = svgCanvas.getId(); + id = svgCanvas.getId() // Remove previous path object if previously created - svgCanvas.removePath_(id); + svgCanvas.removePath_(id) - const newpath = getElem(id); - let newseg; - let sSeg; - const len = seglist.numberOfItems; + 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) { @@ -417,43 +417,43 @@ export const pathActionsMethod = (function () { // otherwise, close the path if (i <= 1 && len >= 2) { // Create end segment - const absX = seglist.getItem(0).x; - const absY = seglist.getItem(0).y; + const absX = seglist.getItem(0).x + const absY = seglist.getItem(0).y - sSeg = stretchy.pathSegList.getItem(1); + sSeg = stretchy.pathSegList.getItem(1) newseg = sSeg.pathSegType === 4 ? drawnPath.createSVGPathSegLinetoAbs(absX, absY) - : drawnPath.createSVGPathSegCurvetoCubicAbs(absX, absY, sSeg.x1 / zoom, sSeg.y1 / zoom, absX, absY); + : drawnPath.createSVGPathSegCurvetoCubicAbs(absX, absY, sSeg.x1 / zoom, sSeg.y1 / zoom, absX, absY) - const endseg = drawnPath.createSVGPathSegClosePath(); - seglist.appendItem(newseg); - seglist.appendItem(endseg); + const endseg = drawnPath.createSVGPathSegClosePath() + seglist.appendItem(newseg) + seglist.appendItem(endseg) } else if (len < 3) { - keep = false; - return keep; + keep = false + return keep } - stretchy.remove(); + 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 = */ svgCanvas.setDrawnPath(null); - svgCanvas.setStarted(false); + /* drawnPath = */ svgCanvas.setDrawnPath(null) + svgCanvas.setStarted(false) if (subpath) { if (path.matrix) { - svgCanvas.remapElement(newpath, {}, path.matrix.inverse()); + svgCanvas.remapElement(newpath, {}, path.matrix.inverse()) } - const newD = newpath.getAttribute('d'); - const origD = path.elem.getAttribute('d'); - path.elem.setAttribute('d', origD + newD); - newpath.parentNode.removeChild(newpath); + const newD = newpath.getAttribute('d') + const origD = path.elem.getAttribute('d') + path.elem.setAttribute('d', origD + newD) + newpath.parentNode.removeChild(newpath) if (path.matrix) { - svgCanvas.recalcRotatedPath(); + svgCanvas.recalcRotatedPath() } - pathActionsMethod.toEditMode(path.elem); - path.selectPt(); - return false; + pathActionsMethod.toEditMode(path.elem) + path.selectPt() + return false } // else, create a new point, update path element } else { @@ -462,20 +462,20 @@ export const pathActionsMethod = (function () { svgCanvas.getMouseTarget(evt) ))) { // Clicked outside canvas, so don't make point - return false; + return false } - const num = drawnPath.pathSegList.numberOfItems; - const last = drawnPath.pathSegList.getItem(num - 1); - const lastx = last.x; const lasty = last.y; + const num = drawnPath.pathSegList.numberOfItems + const last = drawnPath.pathSegList.getItem(num - 1) + const lastx = last.x; const lasty = last.y if (evt.shiftKey) { const xya = snapToAngle(lastx, lasty, x, y); - ({ x, y } = xya); + ({ x, y } = xya) } // Use the segment defined by stretchy - sSeg = stretchy.pathSegList.getItem(1); + sSeg = stretchy.pathSegList.getItem(1) newseg = sSeg.pathSegType === 4 ? drawnPath.createSVGPathSegLinetoAbs(svgCanvas.round(x), svgCanvas.round(y)) : drawnPath.createSVGPathSegCurvetoCubicAbs( @@ -485,77 +485,77 @@ export const pathActionsMethod = (function () { sSeg.y1 / zoom, sSeg.x2 / zoom, sSeg.y2 / zoom - ); + ) - drawnPath.pathSegList.appendItem(newseg); + drawnPath.pathSegList.appendItem(newseg) - x *= zoom; - y *= zoom; + x *= zoom + y *= zoom // set stretchy line to latest point - stretchy.setAttribute('d', [ 'M', x, y, x, y ].join(' ')); - index = num; - if (subpath) { index += path.segs.length; } - svgCanvas.addPointGrip(index, x, y); + stretchy.setAttribute('d', ['M', x, y, x, y].join(' ')) + index = num + if (subpath) { index += path.segs.length } + svgCanvas.addPointGrip(index, x, y) } // keep = true; } - return undefined; + return undefined } // TODO: Make sure currentPath isn't null at this point - if (!path) { return undefined; } + if (!path) { return undefined } path.storeD(); - ({ id } = evt.target); - let 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 ]; - const seg = path.segs[curPt]; + curPt = path.cur_pt = Number.parseInt(id.substr(14)) + path.dragging = [startX, startY] + const seg = path.segs[curPt] // only clear selection if shift is not pressed (otherwise, add // node to selection) if (!evt.shiftKey) { if (path.selected_pts.length <= 1 || !seg.selected) { - path.clearSelection(); + path.clearSelection() } - path.addPtsToSelection(curPt); + path.addPtsToSelection(curPt) } else if (seg.selected) { - path.removePtFromSelection(curPt); + path.removePtFromSelection(curPt) } else { - path.addPtsToSelection(curPt); + path.addPtsToSelection(curPt) } } else if (id.startsWith('ctrlpointgrip_')) { - path.dragging = [ startX, startY ]; + path.dragging = [startX, startY] - const parts = id.split('_')[1].split('c'); - curPt = Number(parts[0]); - const ctrlNum = Number(parts[1]); - path.selectPt(curPt, ctrlNum); + const parts = id.split('_')[1].split('c') + curPt = Number(parts[0]) + const ctrlNum = Number(parts[1]) + path.selectPt(curPt, ctrlNum) } // Start selection box if (!path.dragging) { - let rubberBox = svgCanvas.getRubberBox(); + let rubberBox = svgCanvas.getRubberBox() if (isNullish(rubberBox)) { rubberBox = svgCanvas.setRubberBox( svgCanvas.selectorManager.getRubberBandBox() - ); + ) } - const zoom = svgCanvas.getZoom(); + const zoom = svgCanvas.getZoom() assignAttributes(rubberBox, { x: startX * zoom, y: startY * zoom, width: 0, height: 0, display: 'inline' - }, 100); + }, 100) } - return undefined; + return undefined }, /** * @param {Float} mouseX @@ -563,131 +563,131 @@ export const pathActionsMethod = (function () { * @returns {void} */ mouseMove (mouseX, mouseY) { - const zoom = svgCanvas.getZoom(); - hasMoved = true; - const drawnPath = svgCanvas.getDrawnPath(); + const zoom = svgCanvas.getZoom() + hasMoved = true + const drawnPath = svgCanvas.getDrawnPath() if (svgCanvas.getCurrentMode() === 'path') { - if (!drawnPath) { return; } - const seglist = drawnPath.pathSegList; - const index = seglist.numberOfItems - 1; + if (!drawnPath) { return } + const seglist = drawnPath.pathSegList + const index = seglist.numberOfItems - 1 if (newPoint) { // First point // if (!index) { return; } // Set control points - const pointGrip1 = svgCanvas.addCtrlGrip('1c1'); - const pointGrip2 = svgCanvas.addCtrlGrip('0c2'); + const pointGrip1 = svgCanvas.addCtrlGrip('1c1') + const pointGrip2 = svgCanvas.addCtrlGrip('0c2') // dragging pointGrip1 - pointGrip1.setAttribute('cx', mouseX); - pointGrip1.setAttribute('cy', mouseY); - pointGrip1.setAttribute('display', 'inline'); + pointGrip1.setAttribute('cx', mouseX) + pointGrip1.setAttribute('cy', mouseY) + pointGrip1.setAttribute('display', 'inline') - const ptX = newPoint[0]; - const ptY = newPoint[1]; + const ptX = newPoint[0] + const ptY = newPoint[1] // set curve // const seg = seglist.getItem(index); - const curX = mouseX / zoom; - const curY = mouseY / zoom; - const altX = (ptX + (ptX - curX)); - const altY = (ptY + (ptY - curY)); + const curX = mouseX / zoom + const curY = mouseY / zoom + const altX = (ptX + (ptX - curX)) + const altY = (ptY + (ptY - curY)) - pointGrip2.setAttribute('cx', altX * zoom); - pointGrip2.setAttribute('cy', altY * zoom); - pointGrip2.setAttribute('display', 'inline'); + pointGrip2.setAttribute('cx', altX * zoom) + pointGrip2.setAttribute('cy', altY * zoom) + pointGrip2.setAttribute('display', 'inline') - const ctrlLine = svgCanvas.getCtrlLine(1); + const ctrlLine = svgCanvas.getCtrlLine(1) assignAttributes(ctrlLine, { x1: mouseX, y1: mouseY, x2: altX * zoom, y2: altY * zoom, display: 'inline' - }); + }) if (index === 0) { - firstCtrl = [ mouseX, mouseY ]; + firstCtrl = [mouseX, mouseY] } else { - const last = seglist.getItem(index - 1); - let lastX = last.x; - let 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); - lastY += (lastY - last.y2); + lastX += (lastX - last.x2) + lastY += (lastY - last.y2) } else if (firstCtrl) { - lastX = firstCtrl[0] / zoom; - lastY = firstCtrl[1] / zoom; + lastX = firstCtrl[0] / zoom + lastY = firstCtrl[1] / zoom } - svgCanvas.replacePathSeg(6, index, [ ptX, ptY, lastX, lastY, altX, altY ], drawnPath); + svgCanvas.replacePathSeg(6, index, [ptX, ptY, lastX, lastY, altX, altY], drawnPath) } } else { - const stretchy = getElem('path_stretch_line'); + const stretchy = getElem('path_stretch_line') if (stretchy) { - const prev = seglist.getItem(index); + const prev = seglist.getItem(index) if (prev.pathSegType === 6) { - const prevX = prev.x + (prev.x - prev.x2); - const prevY = prev.y + (prev.y - prev.y2); + const prevX = prev.x + (prev.x - prev.x2) + const prevY = prev.y + (prev.y - prev.y2) svgCanvas.replacePathSeg( 6, 1, - [ mouseX, mouseY, prevX * zoom, prevY * zoom, mouseX, mouseY ], + [mouseX, mouseY, prevX * zoom, prevY * zoom, mouseX, mouseY], stretchy - ); + ) } else if (firstCtrl) { - svgCanvas.replacePathSeg(6, 1, [ mouseX, mouseY, firstCtrl[0], firstCtrl[1], mouseX, mouseY ], stretchy); + svgCanvas.replacePathSeg(6, 1, [mouseX, mouseY, firstCtrl[0], firstCtrl[1], mouseX, mouseY], stretchy) } else { - svgCanvas.replacePathSeg(4, 1, [ mouseX, mouseY ], stretchy); + svgCanvas.replacePathSeg(4, 1, [mouseX, mouseY], stretchy) } } } - return; + return } // if we are dragging a point, let's move it if (path.dragging) { const pt = svgCanvas.getPointFromGrip({ x: path.dragging[0], y: path.dragging[1] - }, path); + }, path) const mpt = svgCanvas.getPointFromGrip({ x: mouseX, y: mouseY - }, path); - const diffX = mpt.x - pt.x; - const diffY = mpt.y - pt.y; - path.dragging = [ mouseX, mouseY ]; + }, path) + const diffX = mpt.x - pt.x + const diffY = mpt.y - pt.y + path.dragging = [mouseX, mouseY] if (path.dragctrl) { - path.moveCtrl(diffX, diffY); + path.moveCtrl(diffX, diffY) } else { - path.movePts(diffX, diffY); + path.movePts(diffX, diffY) } } else { - path.selected_pts = []; + path.selected_pts = [] path.eachSeg(function (_i) { - const seg = this; - if (!seg.next && !seg.prev) { return; } + const seg = this + if (!seg.next && !seg.prev) { return } // const {item} = seg; - const rubberBox = svgCanvas.getRubberBox(); - const rbb = getBBox(rubberBox); + const rubberBox = svgCanvas.getRubberBox() + const rbb = getBBox(rubberBox) - const pt = svgCanvas.getGripPt(seg); + const pt = svgCanvas.getGripPt(seg) const ptBb = { x: pt.x, y: pt.y, width: 0, height: 0 - }; + } - const sel = rectsIntersect(rbb, ptBb); + const sel = rectsIntersect(rbb, ptBb) - this.select(sel); + this.select(sel) // Note that addPtsToSelection is not being run - if (sel) { path.selected_pts.push(seg.index); } - }); + if (sel) { path.selected_pts.push(seg.index) } + }) } }, /** @@ -704,65 +704,65 @@ export const pathActionsMethod = (function () { * @returns {module:path.keepElement|void} */ mouseUp (evt, element, _mouseX, _mouseY) { - const drawnPath = svgCanvas.getDrawnPath(); + const drawnPath = svgCanvas.getDrawnPath() // Create mode if (svgCanvas.getCurrentMode() === 'path') { - newPoint = null; + newPoint = null if (!drawnPath) { - element = getElem(svgCanvas.getId()); - svgCanvas.setStarted(false); - firstCtrl = null; + element = getElem(svgCanvas.getId()) + svgCanvas.setStarted(false) + firstCtrl = null } return { keep: true, element - }; + } } // Edit mode - const rubberBox = svgCanvas.getRubberBox(); + const rubberBox = svgCanvas.getRubberBox() if (path.dragging) { - const lastPt = path.cur_pt; + const lastPt = path.cur_pt - path.dragging = false; - path.dragctrl = false; - path.update(); + path.dragging = false + path.dragctrl = false + path.update() if (hasMoved) { - path.endChanges('Move path point(s)'); + path.endChanges('Move path point(s)') } if (!evt.shiftKey && !hasMoved) { - path.selectPt(lastPt); + path.selectPt(lastPt) } } else if (rubberBox && rubberBox.getAttribute('display') !== 'none') { // Done with multi-node-select - rubberBox.setAttribute('display', 'none'); + rubberBox.setAttribute('display', 'none') if (rubberBox.getAttribute('width') <= 2 && rubberBox.getAttribute('height') <= 2) { - pathActionsMethod.toSelectMode(evt.target); + pathActionsMethod.toSelectMode(evt.target) } // else, move back to select mode } else { - pathActionsMethod.toSelectMode(evt.target); + pathActionsMethod.toSelectMode(evt.target) } - hasMoved = false; - return undefined; + hasMoved = false + return undefined }, /** * @param {Element} element * @returns {void} */ toEditMode (element) { - path = svgCanvas.getPath_(element); - svgCanvas.setCurrentMode('pathedit'); - svgCanvas.clearSelection(); - path.setPathContext(); - path.show(true).update(); - path.oldbbox = getBBox(path.elem); - subpath = false; + path = svgCanvas.getPath_(element) + svgCanvas.setCurrentMode('pathedit') + svgCanvas.clearSelection() + path.setPathContext() + path.show(true).update() + path.oldbbox = getBBox(path.elem) + subpath = false }, /** * @param {Element} elem @@ -770,21 +770,21 @@ export const pathActionsMethod = (function () { * @returns {void} */ toSelectMode (elem) { - const selPath = (elem === path.elem); - svgCanvas.setCurrentMode('select'); - path.setPathContext(); - path.show(false); - currentPath = false; - svgCanvas.clearSelection(); + const selPath = (elem === path.elem) + svgCanvas.setCurrentMode('select') + path.setPathContext() + path.show(false) + currentPath = false + svgCanvas.clearSelection() if (path.matrix) { // Rotated, so may need to re-calculate the center - svgCanvas.recalcRotatedPath(); + svgCanvas.recalcRotatedPath() } if (selPath) { - svgCanvas.call('selected', [ elem ]); - svgCanvas.addToSelection([ elem ], true); + svgCanvas.call('selected', [elem]) + svgCanvas.addToSelection([elem], true) } }, /** @@ -795,11 +795,11 @@ export const pathActionsMethod = (function () { if (on) { // Internally we go into "path" mode, but in the UI it will // still appear as if in "pathedit" mode. - svgCanvas.setCurrentMode('path'); - subpath = true; + svgCanvas.setCurrentMode('path') + subpath = true } else { - pathActionsMethod.clear(true); - pathActionsMethod.toEditMode(path.elem); + pathActionsMethod.clear(true) + pathActionsMethod.toEditMode(path.elem) } }, /** @@ -808,11 +808,11 @@ export const pathActionsMethod = (function () { */ select (target) { if (currentPath === target) { - pathActionsMethod.toEditMode(target); - svgCanvas.setCurrentMode('pathedit'); + pathActionsMethod.toEditMode(target) + svgCanvas.setCurrentMode('pathedit') // going into pathedit mode } else { - currentPath = target; + currentPath = target } }, /** @@ -820,29 +820,29 @@ export const pathActionsMethod = (function () { * @returns {void} */ reorient () { - const elem = svgCanvas.getSelectedElements()[0]; - if (!elem) { return; } - const angl = getRotationAngle(elem); - if (angl === 0) { return; } + const elem = svgCanvas.getSelectedElements()[0] + if (!elem) { return } + const angl = getRotationAngle(elem) + if (angl === 0) { return } - const batchCmd = new BatchCommand('Reorient path'); + const batchCmd = new BatchCommand('Reorient path') const changes = { d: elem.getAttribute('d'), transform: elem.getAttribute('transform') - }; - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - svgCanvas.clearSelection(); - this.resetOrientation(elem); + } + batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)) + svgCanvas.clearSelection() + this.resetOrientation(elem) - svgCanvas.addCommandToHistory(batchCmd); + svgCanvas.addCommandToHistory(batchCmd) // Set matrix to null - svgCanvas.getPath_(elem).show(false).matrix = null; + svgCanvas.getPath_(elem).show(false).matrix = null - this.clear(); + this.clear() - svgCanvas.addToSelection([ elem ], true); - svgCanvas.call('changed', svgCanvas.getSelectedElements()); + svgCanvas.addToSelection([elem], true) + svgCanvas.call('changed', svgCanvas.getSelectedElements()) }, /** @@ -850,44 +850,44 @@ export const pathActionsMethod = (function () { * @returns {void} */ clear () { - const drawnPath = svgCanvas.getDrawnPath(); - currentPath = null; + const drawnPath = svgCanvas.getDrawnPath() + currentPath = null if (drawnPath) { - const elem = getElem(svgCanvas.getId()); - const psl = getElem('path_stretch_line'); - psl.parentNode.removeChild(psl); - elem.parentNode.removeChild(elem); - const pathpointgripContainer = getElem('pathpointgrip_container'); - const elements = pathpointgripContainer.querySelectorAll('*'); - Array.prototype.forEach.call(elements, function(el){ - el.setAttribute('display', 'none'); - }); - firstCtrl = null; - svgCanvas.setDrawnPath(null); - svgCanvas.setStarted(false); + const elem = getElem(svgCanvas.getId()) + const psl = getElem('path_stretch_line') + psl.parentNode.removeChild(psl) + elem.parentNode.removeChild(elem) + const pathpointgripContainer = getElem('pathpointgrip_container') + const elements = pathpointgripContainer.querySelectorAll('*') + Array.prototype.forEach.call(elements, function (el) { + el.setAttribute('display', 'none') + }) + firstCtrl = null + svgCanvas.setDrawnPath(null) + svgCanvas.setStarted(false) } else if (svgCanvas.getCurrentMode() === 'pathedit') { - this.toSelectMode(); + this.toSelectMode() } - if (path) { path.init().show(false); } + if (path) { path.init().show(false) } }, /** * @param {?(Element|SVGPathElement)} pth * @returns {false|void} */ resetOrientation (pth) { - if (isNullish(pth) || pth.nodeName !== 'path') { return false; } - const tlist = pth.transform.baseVal; - const m = transformListToTransform(tlist).matrix; - tlist.clear(); - pth.removeAttribute('transform'); - const segList = pth.pathSegList; + if (isNullish(pth) || pth.nodeName !== 'path') { return false } + const tlist = pth.transform.baseVal + const m = transformListToTransform(tlist).matrix + tlist.clear() + pth.removeAttribute('transform') + 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 { - const len = segList.numberOfItems; + const len = segList.numberOfItems // } catch(err) { // const fixed_d = pathActions.convertPath(pth); // pth.setAttribute('d', fixed_d); @@ -896,29 +896,29 @@ export const pathActionsMethod = (function () { // } // let lastX, lastY; for (let i = 0; i < len; ++i) { - const seg = segList.getItem(i); - const type = seg.pathSegType; - if (type === 1) { continue; } + const seg = segList.getItem(i) + const type = seg.pathSegType + if (type === 1) { continue } const pts = []; - [ '', 1, 2 ].forEach(function(n){ - const x = seg['x' + n]; const y = seg['y' + n]; + ['', 1, 2].forEach(function (n) { + const x = seg['x' + n]; const y = seg['y' + n] if (x !== undefined && y !== undefined) { - const pt = transformPoint(x, y, m); - pts.splice(pts.length, 0, pt.x, pt.y); + const pt = transformPoint(x, y, m) + pts.splice(pts.length, 0, pt.x, pt.y) } - }); - svgCanvas.replacePathSeg(type, i, pts, pth); + }) + svgCanvas.replacePathSeg(type, i, pts, pth) } - svgCanvas.reorientGrads(pth, m); - return undefined; + svgCanvas.reorientGrads(pth, m) + return undefined }, /** * @returns {void} */ zoomChange () { if (svgCanvas.getCurrentMode() === 'pathedit') { - path.update(); + path.update() } }, /** @@ -931,104 +931,104 @@ export const pathActionsMethod = (function () { * @returns {module:path.NodePoint} */ getNodePoint () { - const selPt = path.selected_pts.length ? path.selected_pts[0] : 1; + const selPt = path.selected_pts.length ? path.selected_pts[0] : 1 - const seg = path.segs[selPt]; + const seg = path.segs[selPt] return { x: seg.item.x, y: seg.item.y, type: seg.type - }; + } }, /** * @param {boolean} linkPoints * @returns {void} */ linkControlPoints (linkPoints) { - svgCanvas.setLinkControlPoints(linkPoints); + svgCanvas.setLinkControlPoints(linkPoints) }, /** * @returns {void} */ clonePathNode () { - path.storeD(); + path.storeD() - const selPts = path.selected_pts; + const selPts = path.selected_pts // const {segs} = path; - let i = selPts.length; - const nums = []; + let i = selPts.length + const nums = [] while (i--) { - const pt = selPts[i]; - path.addSeg(pt); + const pt = selPts[i] + path.addSeg(pt) - nums.push(pt + i); - nums.push(pt + i + 1); + nums.push(pt + i) + nums.push(pt + i + 1) } - path.init().addPtsToSelection(nums); + path.init().addPtsToSelection(nums) - path.endChanges('Clone path node(s)'); + path.endChanges('Clone path node(s)') }, /** * @returns {void} */ opencloseSubPath () { - const selPts = path.selected_pts; + const selPts = path.selected_pts // Only allow one selected node for now - if (selPts.length !== 1) { return; } + if (selPts.length !== 1) { return } - const { elem } = path; - const list = elem.pathSegList; + const { elem } = path + const list = elem.pathSegList // const len = list.numberOfItems; - const index = selPts[0]; + const index = selPts[0] - let openPt = null; - let startItem = null; + let openPt = null + let startItem = null // Check if subpath is already open path.eachSeg(function (i) { if (this.type === 2 && i <= index) { - startItem = this.item; + startItem = this.item } - if (i <= index) { return true; } + if (i <= index) { return true } if (this.type === 2) { // Found M first, so open - openPt = i; - return false; + openPt = i + return false } if (this.type === 1) { // Found Z first, so closed - openPt = false; - return false; + openPt = false + return false } - return true; - }); + return true + }) if (isNullish(openPt)) { // Single path, so close last seg - openPt = path.segs.length - 1; + openPt = path.segs.length - 1 } if (openPt !== false) { // Close this path // Create a line going to the previous "M" - const newseg = elem.createSVGPathSegLinetoAbs(startItem.x, startItem.y); + const newseg = elem.createSVGPathSegLinetoAbs(startItem.x, startItem.y) - const closer = elem.createSVGPathSegClosePath(); + const closer = elem.createSVGPathSegClosePath() if (openPt === path.segs.length - 1) { - list.appendItem(newseg); - list.appendItem(closer); + list.appendItem(newseg) + list.appendItem(closer) } else { - list.insertItemBefore(closer, openPt); - list.insertItemBefore(newseg, openPt); + list.insertItemBefore(closer, openPt) + list.insertItemBefore(newseg, openPt) } - path.init().selectPt(openPt + 1); - return; + path.init().selectPt(openPt + 1) + return } // M 1,1 L 2,2 L 3,3 L 1,1 z // open at 2,2 @@ -1037,129 +1037,129 @@ export const pathActionsMethod = (function () { // M 1,1 L 2,2 L 1,1 z M 4,4 L 5,5 L6,6 L 5,5 z // M 1,1 L 2,2 L 1,1 z [M 4,4] L 5,5 L(M)6,6 L 5,5 z - const seg = path.segs[index]; + const seg = path.segs[index] if (seg.mate) { - list.removeItem(index); // Removes last "L" - list.removeItem(index); // Removes the "Z" - path.init().selectPt(index - 1); - return; + list.removeItem(index) // Removes last "L" + list.removeItem(index) // Removes the "Z" + path.init().selectPt(index - 1) + return } - let lastM; let zSeg; + let lastM; let zSeg // Find this sub-path's closing point and remove for (let i = 0; i < list.numberOfItems; i++) { - const item = list.getItem(i); + const item = list.getItem(i) if (item.pathSegType === 2) { // Find the preceding M - lastM = i; + lastM = i } else if (i === index) { // Remove it - list.removeItem(lastM); + list.removeItem(lastM) // index--; } else if (item.pathSegType === 1 && index < i) { // Remove the closing seg of this subpath - zSeg = i - 1; - list.removeItem(i); - break; + zSeg = i - 1 + list.removeItem(i) + break } } - let num = (index - lastM) - 1; + let num = (index - lastM) - 1 while (num--) { - list.insertItemBefore(list.getItem(lastM), zSeg); + list.insertItemBefore(list.getItem(lastM), zSeg) } - const pt = list.getItem(lastM); + const pt = list.getItem(lastM) // Make this point the new "M" - svgCanvas.replacePathSeg(2, lastM, [ pt.x, pt.y ]); + svgCanvas.replacePathSeg(2, lastM, [pt.x, pt.y]) // i = index; // i is local here, so has no effect; what was the intent for this? - path.init().selectPt(0); + path.init().selectPt(0) }, /** * @returns {void} */ deletePathNode () { - if (!pathActionsMethod.canDeleteNodes) { return; } - path.storeD(); + if (!pathActionsMethod.canDeleteNodes) { return } + path.storeD() - const selPts = path.selected_pts; + const selPts = path.selected_pts - let i = selPts.length; + let i = selPts.length while (i--) { - const pt = selPts[i]; - path.deleteSeg(pt); + const pt = selPts[i] + path.deleteSeg(pt) } // Cleanup const cleanup = function () { - const segList = path.elem.pathSegList; - let len = segList.numberOfItems; + const segList = path.elem.pathSegList + let len = segList.numberOfItems const remItems = function (pos, count) { while (count--) { - segList.removeItem(pos); + segList.removeItem(pos) } - }; + } - if (len <= 1) { return true; } + if (len <= 1) { return true } while (len--) { - const item = segList.getItem(len); + const item = segList.getItem(len) if (item.pathSegType === 1) { - const prev = segList.getItem(len - 1); - const 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); - cleanup(); - break; + remItems(len - 1, 2) + cleanup() + break } else if (nprev.pathSegType === 2) { - remItems(len - 2, 3); - cleanup(); - break; + remItems(len - 2, 3) + cleanup() + break } } else if (item.pathSegType === 2 && len > 0) { - const prevType = segList.getItem(len - 1).pathSegType; + const prevType = segList.getItem(len - 1).pathSegType // Path has M M if (prevType === 2) { - remItems(len - 1, 1); - cleanup(); - break; + remItems(len - 1, 1) + cleanup() + break // Entire path ends with Z M } else if (prevType === 1 && segList.numberOfItems - 1 === len) { - remItems(len, 1); - cleanup(); - break; + remItems(len, 1) + cleanup() + break } } } - return false; - }; + return false + } - cleanup(); + cleanup() // Completely delete a path with 1 or 0 segments if (path.elem.pathSegList.numberOfItems <= 1) { - pathActionsMethod.toSelectMode(path.elem); - svgCanvas.canvas.deleteSelectedElements(); - return; + pathActionsMethod.toSelectMode(path.elem) + svgCanvas.canvas.deleteSelectedElements() + return } - path.init(); - path.clearSelection(); + path.init() + path.clearSelection() // TODO: Find right way to select point now // path.selectPt(selPt); if (window.opera) { // Opera repaints incorrectly - path.elem.setAttribute('d', path.elem.getAttribute('d')); + path.elem.setAttribute('d', path.elem.getAttribute('d')) } - path.endChanges('Delete path node(s)'); + path.endChanges('Delete path node(s)') }, // Can't seem to use `@borrows` here, so using `@see` /** @@ -1174,7 +1174,7 @@ export const pathActionsMethod = (function () { * @returns {void} */ setSegType (v) { - path?.setSegType(v); + path?.setSegType(v) }, /** * @param {string} attr @@ -1182,18 +1182,18 @@ export const pathActionsMethod = (function () { * @returns {void} */ moveNode (attr, newValue) { - const selPts = path.selected_pts; - if (!selPts.length) { return; } + const selPts = path.selected_pts + if (!selPts.length) { return } - path.storeD(); + path.storeD() // Get first selected point - const seg = path.segs[selPts[0]]; - const diff = { x: 0, y: 0 }; - diff[attr] = newValue - seg.item[attr]; + const seg = path.segs[selPts[0]] + const diff = { x: 0, y: 0 } + diff[attr] = newValue - seg.item[attr] - seg.move(diff.x, diff.y); - path.endChanges('Move path point'); + seg.move(diff.x, diff.y) + path.endChanges('Move path point') }, /** * @param {Element} elem @@ -1203,24 +1203,24 @@ export const pathActionsMethod = (function () { // 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 - const segList = elem.pathSegList; - const len = segList.numberOfItems; - let lastM; + const segList = elem.pathSegList + const len = segList.numberOfItems + let lastM for (let i = 0; i < len; ++i) { - const item = segList.getItem(i); + const item = segList.getItem(i) if (item.pathSegType === 2) { // 2 => M segment type (move to) - lastM = item; + lastM = item } if (item.pathSegType === 1) { // 1 => Z segment type (close path) - const 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 - const newseg = elem.createSVGPathSegLinetoAbs(lastM.x, lastM.y); - segList.insertItemBefore(newseg, i); + const newseg = elem.createSVGPathSegLinetoAbs(lastM.x, lastM.y) + segList.insertItemBefore(newseg, i) // Can this be done better? - pathActionsMethod.fixEnd(elem); - break; + pathActionsMethod.fixEnd(elem) + break } } } @@ -1232,6 +1232,6 @@ export const pathActionsMethod = (function () { * @see module:path.convertPath */ convertPath - }); -})(); + }) +})() // end pathActions diff --git a/src/svgcanvas/path-method.js b/src/svgcanvas/path-method.js index 9c0bd7e1..45a3ec1d 100644 --- a/src/svgcanvas/path-method.js +++ b/src/svgcanvas/path-method.js @@ -6,17 +6,17 @@ * @copyright 2011 Alexis Deveria, 2011 Jeff Schiller */ -import { NS } from './namespaces.js'; -import { ChangeElementCommand } from './history.js'; +import { NS } from './namespaces.js' +import { ChangeElementCommand } from './history.js' import { transformPoint, getMatrix -} from './math.js'; +} from './math.js' import { assignAttributes, getRotationAngle, isNullish, getElem -} from './utilities.js'; +} from './utilities.js' -let svgCanvas = null; +let svgCanvas = null /** * @function module:path-actions.init @@ -24,8 +24,8 @@ let svgCanvas = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; -}; + svgCanvas = canvas +} /* eslint-disable max-len */ /** @@ -37,12 +37,12 @@ export const init = function (canvas) { */ /* eslint-enable max-len */ export const ptObjToArrMethod = function (type, segItem) { - const segData = svgCanvas.getSegData(); - const props = segData[type]; + const segData = svgCanvas.getSegData() + const props = segData[type] return props.map((prop) => { - return segItem[prop]; - }); -}; + return segItem[prop] + }) +} /** * @function module:path.getGripPt @@ -51,22 +51,22 @@ export const ptObjToArrMethod = function (type, segItem) { * @returns {module:math.XYObject} */ export const getGripPtMethod = function (seg, altPt) { - const { path: pth } = seg; + const { path: pth } = seg let out = { x: altPt ? altPt.x : seg.item.x, y: altPt ? altPt.y : seg.item.y - }; + } if (pth.matrix) { - const pt = transformPoint(out.x, out.y, pth.matrix); - out = pt; + const pt = transformPoint(out.x, out.y, pth.matrix) + out = pt } - const zoom = svgCanvas.getZoom(); - out.x *= zoom; - out.y *= zoom; + const zoom = svgCanvas.getZoom() + out.x *= zoom + out.y *= zoom - return out; -}; + return out +} /** * @function module:path.getPointFromGrip * @param {module:math.XYObject} pt @@ -77,33 +77,33 @@ export const getPointFromGripMethod = function (pt, pth) { const out = { x: pt.x, y: pt.y - }; + } if (pth.matrix) { - pt = transformPoint(out.x, out.y, pth.imatrix); - out.x = pt.x; - out.y = pt.y; + pt = transformPoint(out.x, out.y, pth.imatrix) + out.x = pt.x + out.y = pt.y } - const zoom = svgCanvas.getZoom(); - out.x /= zoom; - out.y /= zoom; + const zoom = svgCanvas.getZoom() + out.x /= zoom + out.y /= zoom - return out; -}; + return out +} /** * @function module:path.getGripContainer * @returns {Element} */ export const getGripContainerMethod = function () { - let c = getElem('pathpointgrip_container'); + let c = getElem('pathpointgrip_container') if (!c) { - const parentElement = getElem('selectorParentGroup'); - c = document.createElementNS(NS.SVG, 'g'); - parentElement.append(c); - c.id = 'pathpointgrip_container'; + const parentElement = getElem('selectorParentGroup') + c = document.createElementNS(NS.SVG, 'g') + parentElement.append(c) + c.id = 'pathpointgrip_container' } - return c; -}; + return c +} /** * Requires prior call to `setUiStrings` if `xlink:title` * to be set on the grip. @@ -115,12 +115,12 @@ export const getGripContainerMethod = function () { */ export const addPointGripMethod = function (index, x, y) { // create the container of all the point grips - const pointGripContainer = getGripContainerMethod(); + const pointGripContainer = getGripContainerMethod() - let pointGrip = getElem('pathpointgrip_' + index); + let pointGrip = getElem('pathpointgrip_' + index) // create it if (!pointGrip) { - pointGrip = document.createElementNS(NS.SVG, 'circle'); + pointGrip = document.createElementNS(NS.SVG, 'circle') const atts = { id: 'pathpointgrip_' + index, display: 'none', @@ -130,21 +130,21 @@ export const addPointGripMethod = function (index, x, y) { 'stroke-width': 2, cursor: 'move', style: 'pointer-events:all' - }; - const uiStrings = svgCanvas.getUIStrings(); - if ('pathNodeTooltip' in uiStrings) { // May be empty if running path.js without svg-editor - atts['xlink:title'] = uiStrings.pathNodeTooltip; } - assignAttributes(pointGrip, atts); - pointGripContainer.append(pointGrip); + const uiStrings = svgCanvas.getUIStrings() + if ('pathNodeTooltip' in uiStrings) { // May be empty if running path.js without svg-editor + atts['xlink:title'] = uiStrings.pathNodeTooltip + } + assignAttributes(pointGrip, atts) + pointGripContainer.append(pointGrip) - const grip = document.getElementById('pathpointgrip_' + index); - grip?.addEventListener("dblclick", () => { - const path = svgCanvas.getPathObj(); + const grip = document.getElementById('pathpointgrip_' + index) + grip?.addEventListener('dblclick', () => { + const path = svgCanvas.getPathObj() if (path) { - path.setSegType(); + path.setSegType() } - }); + }) } if (x && y) { // set up the point grip element and display it @@ -152,10 +152,10 @@ export const addPointGripMethod = function (index, x, y) { cx: x, cy: y, display: 'inline' - }); + }) } - return pointGrip; -}; + return pointGrip +} /** * Requires prior call to `setUiStrings` if `xlink:title` * to be set on the grip. @@ -164,10 +164,10 @@ export const addPointGripMethod = function (index, x, y) { * @returns {SVGCircleElement} */ export const addCtrlGripMethod = function (id) { - let pointGrip = getElem('ctrlpointgrip_' + id); - if (pointGrip) { return pointGrip; } + let pointGrip = getElem('ctrlpointgrip_' + id) + if (pointGrip) { return pointGrip } - pointGrip = document.createElementNS(NS.SVG, 'circle'); + pointGrip = document.createElementNS(NS.SVG, 'circle') const atts = { id: 'ctrlpointgrip_' + id, display: 'none', @@ -177,34 +177,34 @@ export const addCtrlGripMethod = function (id) { 'stroke-width': 1, cursor: 'move', style: 'pointer-events:all' - }; - const uiStrings = svgCanvas.getUIStrings(); - if ('pathCtrlPtTooltip' in uiStrings) { // May be empty if running path.js without svg-editor - atts['xlink:title'] = uiStrings.pathCtrlPtTooltip; } - assignAttributes(pointGrip, atts); - getGripContainerMethod().append(pointGrip); - return pointGrip; -}; + const uiStrings = svgCanvas.getUIStrings() + if ('pathCtrlPtTooltip' in uiStrings) { // May be empty if running path.js without svg-editor + atts['xlink:title'] = uiStrings.pathCtrlPtTooltip + } + assignAttributes(pointGrip, atts) + getGripContainerMethod().append(pointGrip) + return pointGrip +} /** * @function module:path.getCtrlLine * @param {string} id * @returns {SVGLineElement} */ export const getCtrlLineMethod = function (id) { - let ctrlLine = getElem('ctrlLine_' + id); - if (ctrlLine) { return ctrlLine; } + let ctrlLine = getElem('ctrlLine_' + id) + if (ctrlLine) { return ctrlLine } - ctrlLine = document.createElementNS(NS.SVG, 'line'); + ctrlLine = document.createElementNS(NS.SVG, 'line') assignAttributes(ctrlLine, { id: 'ctrlLine_' + id, stroke: '#555', 'stroke-width': 1, style: 'pointer-events:none' - }); - getGripContainerMethod().append(ctrlLine); - return ctrlLine; -}; + }) + getGripContainerMethod().append(ctrlLine) + return ctrlLine +} /** * @function module:path.getPointGrip * @param {Segment} seg @@ -212,44 +212,44 @@ export const getCtrlLineMethod = function (id) { * @returns {SVGCircleElement} */ export const getPointGripMethod = function (seg, update) { - const { index } = seg; - const pointGrip = addPointGripMethod(index); + const { index } = seg + const pointGrip = addPointGripMethod(index) if (update) { - const pt = getGripPtMethod(seg); + const pt = getGripPtMethod(seg) assignAttributes(pointGrip, { cx: pt.x, cy: pt.y, display: 'inline' - }); + }) } - return pointGrip; -}; + return pointGrip +} /** * @function module:path.getControlPoints * @param {Segment} seg * @returns {PlainObject} */ export const getControlPointsMethod = function (seg) { - const { item, index } = seg; - if (!('x1' in item) || !('x2' in item)) { return null; } - const cpt = {}; - /* const pointGripContainer = */ getGripContainerMethod(); + const { item, index } = seg + if (!('x1' in item) || !('x2' in item)) { return null } + const cpt = {} + /* const pointGripContainer = */ getGripContainerMethod() // Note that this is intentionally not seg.prev.item - const path = svgCanvas.getPathObj(); - const prev = path.segs[index - 1].item; + const path = svgCanvas.getPathObj() + const prev = path.segs[index - 1].item - const segItems = [ prev, item ]; + const segItems = [prev, item] for (let i = 1; i < 3; i++) { - const id = index + 'c' + i; + const id = index + 'c' + i - const ctrlLine = cpt['c' + i + '_line'] = getCtrlLineMethod(id); + const ctrlLine = cpt['c' + i + '_line'] = getCtrlLineMethod(id) - const pt = getGripPtMethod(seg, { x: item['x' + i], y: item['y' + i] }); - const gpt = getGripPtMethod(seg, { x: segItems[i - 1].x, y: segItems[i - 1].y }); + const pt = getGripPtMethod(seg, { x: item['x' + i], y: item['y' + i] }) + const gpt = getGripPtMethod(seg, { x: segItems[i - 1].x, y: segItems[i - 1].y }) assignAttributes(ctrlLine, { x1: pt.x, @@ -257,22 +257,22 @@ export const getControlPointsMethod = function (seg) { x2: gpt.x, y2: gpt.y, display: 'inline' - }); + }) - cpt['c' + i + '_line'] = ctrlLine; + cpt['c' + i + '_line'] = ctrlLine // create it - const pointGrip = cpt['c' + i] = addCtrlGripMethod(id); + const pointGrip = cpt['c' + i] = addCtrlGripMethod(id) assignAttributes(pointGrip, { cx: pt.x, cy: pt.y, display: 'inline' - }); - cpt['c' + i] = pointGrip; + }) + cpt['c' + i] = pointGrip } - return cpt; -}; + return cpt +} /** * This replaces the segment at the given index. Type is given as number. * @function module:path.replacePathSeg @@ -283,14 +283,14 @@ export const getControlPointsMethod = function (seg) { * @returns {void} */ export const replacePathSegMethod = function (type, index, pts, elem) { - const path = svgCanvas.getPathObj(); - const pth = elem || path.elem; - const pathFuncs = svgCanvas.getPathFuncs(); - const func = 'createSVGPathSeg' + pathFuncs[type]; - const seg = pth[func](...pts); + const path = svgCanvas.getPathObj() + const pth = elem || path.elem + const pathFuncs = svgCanvas.getPathFuncs() + const func = 'createSVGPathSeg' + pathFuncs[type] + const seg = pth[func](...pts) - pth.pathSegList.replaceItem(seg, index); -}; + pth.pathSegList.replaceItem(seg, index) +} /** * @function module:path.getSegSelector * @param {Segment} seg @@ -298,12 +298,12 @@ export const replacePathSegMethod = function (type, index, pts, elem) { * @returns {SVGPathElement} */ export const getSegSelectorMethod = function (seg, update) { - const { index } = seg; - let segLine = getElem('segline_' + index); + const { index } = seg + let segLine = getElem('segline_' + index) if (!segLine) { - const pointGripContainer = getGripContainerMethod(); + const pointGripContainer = getGripContainerMethod() // create segline - segLine = document.createElementNS(NS.SVG, 'path'); + segLine = document.createElementNS(NS.SVG, 'path') assignAttributes(segLine, { id: 'segline_' + index, display: 'none', @@ -312,32 +312,32 @@ export const getSegSelectorMethod = function (seg, update) { 'stroke-width': 2, style: 'pointer-events:none', d: 'M0,0 0,0' - }); - pointGripContainer.append(segLine); + }) + pointGripContainer.append(segLine) } if (update) { - const { prev } = seg; + const { prev } = seg if (!prev) { - segLine.setAttribute('display', 'none'); - return segLine; + segLine.setAttribute('display', 'none') + return segLine } - const pt = getGripPtMethod(prev); + const pt = getGripPtMethod(prev) // Set start point - replacePathSegMethod(2, 0, [ pt.x, pt.y ], segLine); + replacePathSegMethod(2, 0, [pt.x, pt.y], segLine) - const pts = ptObjToArrMethod(seg.type, seg.item); // , true); + const pts = ptObjToArrMethod(seg.type, seg.item) // , true); for (let i = 0; i < pts.length; i += 2) { - const point = getGripPtMethod(seg, { x: pts[i], y: pts[i + 1] }); - pts[i] = point.x; - pts[i + 1] = point.y; + const point = getGripPtMethod(seg, { x: pts[i], y: pts[i + 1] }) + pts[i] = point.x + pts[i + 1] = point.y } - replacePathSegMethod(seg.type, 1, pts, segLine); + replacePathSegMethod(seg.type, 1, pts, segLine) } - return segLine; -}; + return segLine +} /** * */ @@ -348,14 +348,14 @@ export class Segment { * @todo Is `item` be more constrained here? */ constructor (index, item) { - this.selected = false; - this.index = index; - this.item = item; - this.type = item.pathSegType; + this.selected = false + this.index = index + this.item = item + this.type = item.pathSegType - this.ctrlpts = []; - this.ptgrip = null; - this.segsel = null; + this.ctrlpts = [] + this.ptgrip = null + this.segsel = null } /** @@ -365,7 +365,7 @@ export class Segment { showCtrlPts (y) { for (const i in this.ctrlpts) { if ({}.hasOwnProperty.call(this.ctrlpts, i)) { - this.ctrlpts[i].setAttribute('display', y ? 'inline' : 'none'); + this.ctrlpts[i].setAttribute('display', y ? 'inline' : 'none') } } } @@ -375,8 +375,8 @@ export class Segment { * @returns {void} */ selectCtrls (y) { - document.getElementById('ctrlpointgrip_' + this.index + 'c1').setAttribute('fill', y ? '#0FF' : '#EEE'); - document.getElementById('ctrlpointgrip_' + this.index + 'c2').setAttribute('fill', y ? '#0FF' : '#EEE'); + document.getElementById('ctrlpointgrip_' + this.index + 'c1').setAttribute('fill', y ? '#0FF' : '#EEE') + document.getElementById('ctrlpointgrip_' + this.index + 'c2').setAttribute('fill', y ? '#0FF' : '#EEE') } /** @@ -385,10 +385,10 @@ export class Segment { */ show (y) { if (this.ptgrip) { - this.ptgrip.setAttribute('display', y ? 'inline' : 'none'); - this.segsel.setAttribute('display', y ? 'inline' : 'none'); + this.ptgrip.setAttribute('display', y ? 'inline' : 'none') + this.segsel.setAttribute('display', y ? 'inline' : 'none') // Show/hide all control points if available - this.showCtrlPts(y); + this.showCtrlPts(y) } } @@ -398,12 +398,12 @@ export class Segment { */ select (y) { if (this.ptgrip) { - this.ptgrip.setAttribute('stroke', y ? '#0FF' : '#00F'); - this.segsel.setAttribute('display', y ? 'inline' : 'none'); + this.ptgrip.setAttribute('stroke', y ? '#0FF' : '#00F') + this.segsel.setAttribute('display', y ? 'inline' : 'none') if (this.ctrlpts) { - this.selectCtrls(y); + this.selectCtrls(y) } - this.selected = y; + this.selected = y } } @@ -411,9 +411,9 @@ export class Segment { * @returns {void} */ addGrip () { - this.ptgrip = getPointGripMethod(this, true); - this.ctrlpts = getControlPointsMethod(this); // , true); - this.segsel = getSegSelectorMethod(this, true); + this.ptgrip = getPointGripMethod(this, true) + this.ctrlpts = getControlPointsMethod(this) // , true); + this.segsel = getSegSelectorMethod(this, true) } /** @@ -422,21 +422,21 @@ export class Segment { */ update (full) { if (this.ptgrip) { - const pt = getGripPtMethod(this); + const pt = getGripPtMethod(this) assignAttributes(this.ptgrip, { cx: pt.x, cy: pt.y - }); + }) - getSegSelectorMethod(this, true); + getSegSelectorMethod(this, true) if (this.ctrlpts) { if (full) { - const path = svgCanvas.getPathObj(); - this.item = path.elem.pathSegList.getItem(this.index); - this.type = this.item.pathSegType; + const path = svgCanvas.getPathObj() + this.item = path.elem.pathSegList.getItem(this.index) + this.type = this.item.pathSegType } - getControlPointsMethod(this); + getControlPointsMethod(this) } // this.segsel.setAttribute('display', y ? 'inline' : 'none'); } @@ -448,42 +448,42 @@ export class Segment { * @returns {void} */ move (dx, dy) { - const { item } = this; + 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 ]; + item.x += dx, item.y += dy, + item.x1, item.y1, item.x2 += dx, item.y2 += dy + ] + : [item.x += dx, item.y += dy] replacePathSegMethod( this.type, this.index, // type 10 means ARC this.type === 10 ? ptObjToArrMethod(this.type, item) : curPts - ); + ) if (this.next && this.next.ctrlpts) { - const next = this.next.item; + const next = this.next.item const nextPts = [ next.x, next.y, next.x1 += dx, next.y1 += dy, next.x2, next.y2 - ]; - replacePathSegMethod(this.next.type, this.next.index, nextPts); + ] + replacePathSegMethod(this.next.type, this.next.index, nextPts) } 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 ]; - replacePathSegMethod(this.mate.type, this.mate.index, pts); + const { item: itm } = this.mate + const pts = [itm.x += dx, itm.y += dy] + replacePathSegMethod(this.mate.type, this.mate.index, pts) // Has no grip, so does not need 'updating'? } - this.update(true); - if (this.next) { this.next.update(true); } + this.update(true) + if (this.next) { this.next.update(true) } } /** @@ -491,31 +491,31 @@ export class Segment { * @returns {void} */ setLinked (num) { - let seg; let anum; let pt; + let seg; let anum; let pt if (num === 2) { - anum = 1; - seg = this.next; - if (!seg) { return; } - pt = this.item; + anum = 1 + seg = this.next + if (!seg) { return } + pt = this.item } else { - anum = 2; - seg = this.prev; - if (!seg) { return; } - pt = seg.item; + anum = 2 + seg = this.prev + if (!seg) { return } + pt = seg.item } - 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 { 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 - ]; + ] - replacePathSegMethod(seg.type, seg.index, pts); - seg.update(true); + replacePathSegMethod(seg.type, seg.index, pts) + seg.update(true) } /** @@ -525,17 +525,17 @@ export class Segment { * @returns {void} */ moveCtrl (num, dx, dy) { - const { item } = this; - item['x' + num] += dx; - item['y' + num] += 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 - ]; + ] - replacePathSegMethod(this.type, this.index, pts); - this.update(true); + replacePathSegMethod(this.type, this.index, pts) + this.update(true) } /** @@ -544,13 +544,13 @@ export class Segment { * @returns {void} */ setType (newType, pts) { - replacePathSegMethod(newType, this.index, pts); - this.type = newType; - const path = svgCanvas.getPathObj(); - this.item = path.elem.pathSegList.getItem(this.index); - this.showCtrlPts(newType === 6); - this.ctrlpts = getControlPointsMethod(this); - this.update(true); + replacePathSegMethod(newType, this.index, pts) + this.type = newType + const path = svgCanvas.getPathObj() + this.item = path.elem.pathSegList.getItem(this.index) + this.showCtrlPts(newType === 6) + this.ctrlpts = getControlPointsMethod(this) + this.update(true) } } @@ -564,20 +564,20 @@ export class Path { */ constructor (elem) { if (!elem || elem.tagName !== 'path') { - throw new Error('svgedit.path.Path constructed without a element'); + throw new Error('svgedit.path.Path constructed without a element') } - this.elem = elem; - this.segs = []; - this.selected_pts = []; - svgCanvas.setPathObj(this); + this.elem = elem + this.segs = [] + this.selected_pts = [] + svgCanvas.setPathObj(this) // path = this; - this.init(); + this.init() } - setPathContext() { - svgCanvas.setPathObj(this); + setPathContext () { + svgCanvas.setPathObj(this) } /** @@ -588,83 +588,83 @@ export class Path { // Hide all grips, etc // fixed, needed to work on all found elements, not just first - const pointGripContainer = getGripContainerMethod(); - const elements = pointGripContainer.querySelectorAll('*'); - Array.prototype.forEach.call(elements, function(el){ - el.setAttribute('display', 'none'); - }); + const pointGripContainer = getGripContainerMethod() + const elements = pointGripContainer.querySelectorAll('*') + Array.prototype.forEach.call(elements, function (el) { + el.setAttribute('display', 'none') + }) - const segList = this.elem.pathSegList; - const len = segList.numberOfItems; - this.segs = []; - this.selected_pts = []; - this.first_seg = null; + const segList = this.elem.pathSegList + const len = segList.numberOfItems + this.segs = [] + this.selected_pts = [] + this.first_seg = null // Set up segs array 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); + const item = segList.getItem(i) + const segment = new Segment(i, item) + segment.path = this + this.segs.push(segment) } - const { segs } = this; + const { segs } = this - let startI = null; + let startI = null 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]; + 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 - const startSeg = segs[startI]; - startSeg.next = segs[startI + 1]; - startSeg.next.prev = startSeg; - startSeg.addGrip(); + const startSeg = segs[startI] + startSeg.next = segs[startI + 1] + startSeg.next.prev = startSeg + startSeg.addGrip() } // Remember that this is a starter seg - startI = i; + 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]; + seg.next = segs[startI + 1] // First seg after "M"'s prev is this - seg.next.prev = seg; - seg.mate = segs[startI]; - seg.addGrip(); + seg.next.prev = seg + seg.mate = segs[startI] + seg.addGrip() if (isNullish(this.first_seg)) { - this.first_seg = 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(); + const 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]; + this.first_seg = segs[startI] } } } else if (seg.type !== 1) { // Regular segment, so add grip and its "next" - seg.addGrip(); + seg.addGrip() // Don't set its "next" if it's an "M" if (nextSeg && nextSeg.type !== 2) { - seg.next = nextSeg; - seg.next.prev = seg; + seg.next = nextSeg + seg.next.prev = seg } } } - return this; + return this } /** @@ -678,10 +678,10 @@ export class Path { * @returns {void} */ eachSeg (fn) { - const len = this.segs.length; + const len = this.segs.length for (let i = 0; i < len; i++) { - const ret = fn.call(this.segs[i], i); - if (ret === false) { break; } + const ret = fn.call(this.segs[i], i) + if (ret === false) { break } } } @@ -691,39 +691,39 @@ export class Path { */ addSeg (index) { // Adds a new segment - const seg = this.segs[index]; - if (!seg.prev) { return; } + const seg = this.segs[index] + if (!seg.prev) { return } - const { prev } = seg; - let newseg; let newX; let newY; + const { prev } = seg + let newseg; let newX; let 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) + 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 ]; - replacePathSegMethod(seg.type, index, pts); - break; + 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] + replacePathSegMethod(seg.type, index, pts) + break + } } - } - const list = this.elem.pathSegList; - list.insertItemBefore(newseg, index); + const list = this.elem.pathSegList + list.insertItemBefore(newseg, index) } /** @@ -731,28 +731,28 @@ export class Path { * @returns {void} */ deleteSeg (index) { - const seg = this.segs[index]; - const list = this.elem.pathSegList; + const seg = this.segs[index] + const list = this.elem.pathSegList - seg.show(false); - const { next } = seg; + 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 ]; - replacePathSegMethod(2, next.index, pt); + const pt = [next.item.x, next.item.y] + replacePathSegMethod(2, next.index, pt) // Reposition last node - replacePathSegMethod(4, seg.index, pt); + replacePathSegMethod(4, seg.index, pt) - list.removeItem(seg.mate.index); + 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 ]; - replacePathSegMethod(2, seg.next.index, pt); - list.removeItem(index); + const pt = [next.item.x, next.item.y] + replacePathSegMethod(2, seg.next.index, pt) + list.removeItem(index) } else { - list.removeItem(index); + list.removeItem(index) } } @@ -761,12 +761,12 @@ export class Path { * @returns {void} */ removePtFromSelection (index) { - const pos = this.selected_pts.indexOf(index); + const pos = this.selected_pts.indexOf(index) if (pos === -1) { - return; + return } - this.segs[index].select(false); - this.selected_pts.splice(pos, 1); + this.segs[index].select(false) + this.selected_pts.splice(pos, 1) } /** @@ -775,16 +775,16 @@ export class Path { clearSelection () { this.eachSeg(function () { // 'this' is the segment here - this.select(false); - }); - this.selected_pts = []; + this.select(false) + }) + this.selected_pts = [] } /** * @returns {void} */ storeD () { - this.last_d = this.elem.getAttribute('d'); + this.last_d = this.elem.getAttribute('d') } /** @@ -795,12 +795,12 @@ export class Path { // Shows this path's segment grips this.eachSeg(function () { // 'this' is the segment here - this.show(y); - }); + this.show(y) + }) if (y) { - this.selectPt(this.first_seg.index); + this.selectPt(this.first_seg.index) } - return this; + return this } /** @@ -810,10 +810,10 @@ export class Path { * @returns {void} */ movePts (dx, dy) { - let i = this.selected_pts.length; + let i = this.selected_pts.length while (i--) { - const seg = this.segs[this.selected_pts[i]]; - seg.move(dx, dy); + const seg = this.segs[this.selected_pts[i]] + seg.move(dx, dy) } } @@ -823,10 +823,10 @@ export class Path { * @returns {void} */ moveCtrl (dx, dy) { - const seg = this.segs[this.selected_pts[0]]; - seg.moveCtrl(this.dragctrl, dx, dy); + const seg = this.segs[this.selected_pts[0]] + seg.moveCtrl(this.dragctrl, dx, dy) if (svgCanvas.getLinkControlPts()) { - seg.setLinked(this.dragctrl); + seg.setLinked(this.dragctrl) } } @@ -835,69 +835,69 @@ export class Path { * @returns {void} */ setSegType (newType) { - this.storeD(); - let i = this.selected_pts.length; - let text; + this.storeD() + let i = this.selected_pts.length + let text while (i--) { - const selPt = this.selected_pts[i]; + const selPt = this.selected_pts[i] // Selected seg - const cur = this.segs[selPt]; - const { prev } = cur; - if (!prev) { continue; } + const cur = this.segs[selPt] + const { prev } = cur + if (!prev) { continue } if (!newType) { // double-click, so just toggle - text = 'Toggle Path Segment Type'; + text = 'Toggle Path Segment Type' // Toggle segment to curve/straight line - const oldType = cur.type; + const oldType = cur.type - newType = (oldType === 6) ? 4 : 6; + newType = (oldType === 6) ? 4 : 6 } - newType = Number(newType); + 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; + 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: { - 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 - /* + case 6: { + 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 ]; + // 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 } - break; - } case 4: { - points = [ curX, curY ]; - - // Store original prevve segment nums - cur.olditem = cur.item; - break; - } } - cur.setType(newType, points); + cur.setType(newType, points) } - const path = svgCanvas.getPathObj(); - path.endChanges(text); + const path = svgCanvas.getPathObj() + path.endChanges(text) } /** @@ -906,21 +906,21 @@ export class Path { * @returns {void} */ selectPt (pt, ctrlNum) { - this.clearSelection(); + this.clearSelection() if (isNullish(pt)) { this.eachSeg(function (i) { // 'this' is the segment here. if (this.prev) { - pt = i; + pt = i } - }); + }) } - this.addPtsToSelection(pt); + this.addPtsToSelection(pt) if (ctrlNum) { - this.dragctrl = ctrlNum; + this.dragctrl = ctrlNum if (svgCanvas.getLinkControlPts()) { - this.segs[pt].setLinked(ctrlNum); + this.segs[pt].setLinked(ctrlNum) } } } @@ -930,21 +930,21 @@ export class Path { * @returns {Path} */ update () { - const { elem } = this; + const { elem } = this if (getRotationAngle(elem)) { - this.matrix = getMatrix(elem); - this.imatrix = this.matrix.inverse(); + this.matrix = getMatrix(elem) + this.imatrix = this.matrix.inverse() } else { - this.matrix = null; - this.imatrix = null; + this.matrix = null + this.imatrix = null } this.eachSeg(function (i) { - this.item = elem.pathSegList.getItem(i); - this.update(); - }); + this.item = elem.pathSegList.getItem(i) + this.update() + }) - return this; + return this } /** @@ -952,8 +952,8 @@ export class Path { * @returns {void} */ endChanges (text) { - const cmd = new ChangeElementCommand(this.elem, { d: this.last_d }, text); - svgCanvas.endChanges({ cmd, elem: this.elem }); + const cmd = new ChangeElementCommand(this.elem, { d: this.last_d }, text) + svgCanvas.endChanges({ cmd, elem: this.elem }) } /** @@ -961,27 +961,27 @@ export class Path { * @returns {void} */ addPtsToSelection (indexes) { - if (!Array.isArray(indexes)) { indexes = [ indexes ]; } + if (!Array.isArray(indexes)) { indexes = [indexes] } indexes.forEach((index) => { - const seg = this.segs[index]; + const seg = this.segs[index] if (seg.ptgrip && !this.selected_pts.includes(index) && index >= 0) { - this.selected_pts.push(index); + this.selected_pts.push(index) } - }); - this.selected_pts.sort(); - let i = this.selected_pts.length; - const grips = []; - grips.length = i; + }) + this.selected_pts.sort() + let i = this.selected_pts.length + const grips = [] + grips.length = i // Loop through points to be selected and highlight each while (i--) { - const pt = this.selected_pts[i]; - const seg = this.segs[pt]; - seg.select(true); - grips[i] = seg.ptgrip; + const pt = this.selected_pts[i] + const seg = this.segs[pt] + seg.select(true) + grips[i] = seg.ptgrip } - const closedSubpath = Path.subpathIsClosed(this.selected_pts[0]); - svgCanvas.addPtsToSelection({ grips, closedSubpath }); + const closedSubpath = Path.subpathIsClosed(this.selected_pts[0]) + svgCanvas.addPtsToSelection({ grips, closedSubpath }) } // STATIC @@ -990,23 +990,23 @@ export class Path { * @returns {boolean} */ static subpathIsClosed (index) { - let clsd = false; + let clsd = false // Check if subpath is already open - const path = svgCanvas.getPathObj(); + const path = svgCanvas.getPathObj() path.eachSeg(function (i) { - if (i <= index) { return true; } + if (i <= index) { return true } if (this.type === 2) { // Found M first, so open - return false; + return false } if (this.type === 1) { // Found Z first, so closed - clsd = true; - return false; + clsd = true + return false } - return true; - }); + return true + }) - return clsd; + return clsd } } diff --git a/src/svgcanvas/path.js b/src/svgcanvas/path.js index 8ad3d72d..dff592e8 100644 --- a/src/svgcanvas/path.js +++ b/src/svgcanvas/path.js @@ -6,59 +6,59 @@ * @copyright 2011 Alexis Deveria, 2011 Jeff Schiller */ -import { shortFloat } from '../common/units.js'; -import { transformPoint } from './math.js'; +import { shortFloat } from '../common/units.js' +import { transformPoint } from './math.js' import { getRotationAngle, getBBox, getRefElem, findDefs, isNullish, getBBox as utilsGetBBox -} from './utilities.js'; +} from './utilities.js' import { init as pathMethodInit, ptObjToArrMethod, getGripPtMethod, getPointFromGripMethod, addPointGripMethod, getGripContainerMethod, addCtrlGripMethod, getCtrlLineMethod, getPointGripMethod, getControlPointsMethod, replacePathSegMethod, getSegSelectorMethod, Path -} from './path-method.js'; +} from './path-method.js' import { init as pathActionsInit, pathActionsMethod -} from './path-actions.js'; +} from './path-actions.js' const segData = { - 2: [ 'x', 'y' ], // PATHSEG_MOVETO_ABS - 4: [ 'x', 'y' ], // PATHSEG_LINETO_ABS - 6: [ 'x', 'y', 'x1', 'y1', 'x2', 'y2' ], // PATHSEG_CURVETO_CUBIC_ABS - 8: [ 'x', 'y', 'x1', 'y1' ], // PATHSEG_CURVETO_QUADRATIC_ABS - 10: [ 'x', 'y', 'r1', 'r2', 'angle', 'largeArcFlag', 'sweepFlag' ], // PATHSEG_ARC_ABS - 12: [ 'x' ], // PATHSEG_LINETO_HORIZONTAL_ABS - 14: [ 'y' ], // PATHSEG_LINETO_VERTICAL_ABS - 16: [ 'x', 'y', 'x2', 'y2' ], // PATHSEG_CURVETO_CUBIC_SMOOTH_ABS - 18: [ 'x', 'y' ] // PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS -}; + 2: ['x', 'y'], // PATHSEG_MOVETO_ABS + 4: ['x', 'y'], // PATHSEG_LINETO_ABS + 6: ['x', 'y', 'x1', 'y1', 'x2', 'y2'], // PATHSEG_CURVETO_CUBIC_ABS + 8: ['x', 'y', 'x1', 'y1'], // PATHSEG_CURVETO_QUADRATIC_ABS + 10: ['x', 'y', 'r1', 'r2', 'angle', 'largeArcFlag', 'sweepFlag'], // PATHSEG_ARC_ABS + 12: ['x'], // PATHSEG_LINETO_HORIZONTAL_ABS + 14: ['y'], // PATHSEG_LINETO_VERTICAL_ABS + 16: ['x', 'y', 'x2', 'y2'], // PATHSEG_CURVETO_CUBIC_SMOOTH_ABS + 18: ['x', 'y'] // PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS +} -let svgCanvas; +let svgCanvas /** * @tutorial LocaleDocs * @typedef {module:locale.LocaleStrings|PlainObject} module:path.uiStrings * @property {PlainObject} ui */ -const uiStrings = {}; +const uiStrings = {} /** * @function module:path.setUiStrings * @param {module:path.uiStrings} strs * @returns {void} */ export const setUiStrings = (strs) => { - Object.assign(uiStrings, strs.ui); -}; + Object.assign(uiStrings, strs.ui) +} -let pathFuncs = []; +let pathFuncs = [] -let linkControlPts = true; +let linkControlPts = true // Stores references to paths via IDs. // TODO: Make this cross-document happy. -let pathData = {}; +let pathData = {} /** * @function module:path.setLinkControlPoints @@ -66,15 +66,15 @@ let pathData = {}; * @returns {void} */ export const setLinkControlPoints = (lcp) => { - linkControlPts = lcp; -}; + linkControlPts = lcp +} /** * @name module:path.path * @type {null|module:path.Path} * @memberof module:path */ -export let path = null; +export let path = null /** * @external MouseEvent @@ -229,36 +229,35 @@ export let path = null; * @returns {void} */ export const init = (canvas) => { - svgCanvas = canvas; - svgCanvas.replacePathSeg = replacePathSegMethod; - svgCanvas.addPointGrip = addPointGripMethod; - svgCanvas.removePath_ = removePath_; - svgCanvas.getPath_ = getPath_; - svgCanvas.addCtrlGrip = addCtrlGripMethod; - svgCanvas.getCtrlLine = getCtrlLineMethod; - svgCanvas.getGripPt = getGripPt; - svgCanvas.getPointFromGrip = getPointFromGripMethod; - svgCanvas.setLinkControlPoints = setLinkControlPoints; - svgCanvas.reorientGrads = reorientGrads; - svgCanvas.getSegData = () => { return segData; }; - svgCanvas.getUIStrings= () => { return uiStrings; }; - svgCanvas.getPathObj = () => { return path; }; - svgCanvas.setPathObj = (obj) => { path = obj; }; - svgCanvas.getPathFuncs = () => { return pathFuncs; }; - svgCanvas.getLinkControlPts = () => { return linkControlPts; }; - pathFuncs = [ 0, 'ClosePath' ]; + svgCanvas = canvas + svgCanvas.replacePathSeg = replacePathSegMethod + svgCanvas.addPointGrip = addPointGripMethod + svgCanvas.removePath_ = removePath_ + svgCanvas.getPath_ = getPath_ + svgCanvas.addCtrlGrip = addCtrlGripMethod + svgCanvas.getCtrlLine = getCtrlLineMethod + svgCanvas.getGripPt = getGripPt + svgCanvas.getPointFromGrip = getPointFromGripMethod + svgCanvas.setLinkControlPoints = setLinkControlPoints + svgCanvas.reorientGrads = reorientGrads + svgCanvas.getSegData = () => { return segData } + svgCanvas.getUIStrings = () => { return uiStrings } + svgCanvas.getPathObj = () => { return path } + svgCanvas.setPathObj = (obj) => { path = obj } + svgCanvas.getPathFuncs = () => { return pathFuncs } + svgCanvas.getLinkControlPts = () => { return linkControlPts } + pathFuncs = [0, 'ClosePath'] const pathFuncsStrs = [ 'Moveto', 'Lineto', 'CurvetoCubic', 'CurvetoQuadratic', 'Arc', 'LinetoHorizontal', 'LinetoVertical', 'CurvetoCubicSmooth', 'CurvetoQuadraticSmooth' - ]; + ] pathFuncsStrs.forEach((s) => { - pathFuncs.push(s + 'Abs'); - pathFuncs.push(s + 'Rel'); - }); - pathActionsInit(svgCanvas); - pathMethodInit(svgCanvas); - -}; + pathFuncs.push(s + 'Abs') + pathFuncs.push(s + 'Rel') + }) + pathActionsInit(svgCanvas) + pathMethodInit(svgCanvas) +} /* eslint-disable max-len */ /** @@ -269,7 +268,7 @@ export const init = (canvas) => { * @returns {ArgumentsArray} */ /* eslint-enable max-len */ -export const ptObjToArr = ptObjToArrMethod; +export const ptObjToArr = ptObjToArrMethod /** * @function module:path.getGripPt @@ -277,7 +276,7 @@ export const ptObjToArr = ptObjToArrMethod; * @param {module:math.XYObject} altPt * @returns {module:math.XYObject} */ -export const getGripPt = getGripPtMethod; +export const getGripPt = getGripPtMethod /** * @function module:path.getPointFromGrip @@ -285,7 +284,7 @@ export const getGripPt = getGripPtMethod; * @param {module:path.Path} pth * @returns {module:math.XYObject} */ -export const getPointFromGrip = getPointFromGripMethod; +export const getPointFromGrip = getPointFromGripMethod /** * Requires prior call to `setUiStrings` if `xlink:title` @@ -296,13 +295,13 @@ export const getPointFromGrip = getPointFromGripMethod; * @param {Integer} y * @returns {SVGCircleElement} */ -export const addPointGrip = addPointGripMethod; +export const addPointGrip = addPointGripMethod /** * @function module:path.getGripContainer * @returns {Element} */ -export const getGripContainer = getGripContainerMethod; +export const getGripContainer = getGripContainerMethod /** * Requires prior call to `setUiStrings` if `xlink:title` @@ -311,14 +310,14 @@ export const getGripContainer = getGripContainerMethod; * @param {string} id * @returns {SVGCircleElement} */ -export const addCtrlGrip = addCtrlGripMethod; +export const addCtrlGrip = addCtrlGripMethod /** * @function module:path.getCtrlLine * @param {string} id * @returns {SVGLineElement} */ -export const getCtrlLine = getCtrlLineMethod; +export const getCtrlLine = getCtrlLineMethod /** * @function module:path.getPointGrip @@ -326,14 +325,14 @@ export const getCtrlLine = getCtrlLineMethod; * @param {boolean} update * @returns {SVGCircleElement} */ -export const getPointGrip = getPointGripMethod; +export const getPointGrip = getPointGripMethod /** * @function module:path.getControlPoints * @param {Segment} seg * @returns {PlainObject} */ -export const getControlPoints = getControlPointsMethod; +export const getControlPoints = getControlPointsMethod /** * This replaces the segment at the given index. Type is given as number. @@ -344,7 +343,7 @@ export const getControlPoints = getControlPointsMethod; * @param {SVGPathElement} elem * @returns {void} */ -export const replacePathSeg = replacePathSegMethod; +export const replacePathSeg = replacePathSegMethod /** * @function module:path.getSegSelector @@ -352,7 +351,7 @@ export const replacePathSeg = replacePathSegMethod; * @param {boolean} update * @returns {SVGPathElement} */ -export const getSegSelector = getSegSelectorMethod; +export const getSegSelector = getSegSelectorMethod /** * @typedef {PlainObject} Point @@ -370,44 +369,44 @@ export const getSegSelector = getSegSelectorMethod; */ export const smoothControlPoints = (ct1, ct2, pt) => { // each point must not be the origin - const x1 = ct1.x - pt.x; - const y1 = ct1.y - pt.y; - const x2 = ct2.x - pt.x; - const y2 = ct2.y - pt.y; + const x1 = ct1.x - pt.x + const y1 = ct1.y - pt.y + const x2 = ct2.x - pt.x + const y2 = ct2.y - pt.y if ((x1 !== 0 || y1 !== 0) && (x2 !== 0 || y2 !== 0)) { const - r1 = Math.sqrt(x1 * x1 + y1 * y1); - const r2 = Math.sqrt(x2 * x2 + y2 * y2); - const nct1 = svgCanvas.getSvgRoot().createSVGPoint(); - const nct2 = svgCanvas.getSvgRoot().createSVGPoint(); - let anglea = Math.atan2(y1, x1); - let angleb = Math.atan2(y2, x2); - if (anglea < 0) { anglea += 2 * Math.PI; } - if (angleb < 0) { angleb += 2 * Math.PI; } + r1 = Math.sqrt(x1 * x1 + y1 * y1) + const r2 = Math.sqrt(x2 * x2 + y2 * y2) + const nct1 = svgCanvas.getSvgRoot().createSVGPoint() + const nct2 = svgCanvas.getSvgRoot().createSVGPoint() + let anglea = Math.atan2(y1, x1) + let angleb = Math.atan2(y2, x2) + if (anglea < 0) { anglea += 2 * Math.PI } + if (angleb < 0) { angleb += 2 * Math.PI } - const angleBetween = Math.abs(anglea - angleb); - const angleDiff = Math.abs(Math.PI - angleBetween) / 2; + const angleBetween = Math.abs(anglea - angleb) + const angleDiff = Math.abs(Math.PI - angleBetween) / 2 - let newAnglea; let newAngleb; + let newAnglea; let newAngleb if (anglea - angleb > 0) { - newAnglea = angleBetween < Math.PI ? (anglea + angleDiff) : (anglea - angleDiff); - newAngleb = angleBetween < Math.PI ? (angleb - angleDiff) : (angleb + angleDiff); + newAnglea = angleBetween < Math.PI ? (anglea + angleDiff) : (anglea - angleDiff) + newAngleb = angleBetween < Math.PI ? (angleb - angleDiff) : (angleb + angleDiff) } else { - newAnglea = angleBetween < Math.PI ? (anglea - angleDiff) : (anglea + angleDiff); - newAngleb = angleBetween < Math.PI ? (angleb + angleDiff) : (angleb - angleDiff); + newAnglea = angleBetween < Math.PI ? (anglea - angleDiff) : (anglea + angleDiff) + newAngleb = angleBetween < Math.PI ? (angleb + angleDiff) : (angleb - angleDiff) } // rotate the points - nct1.x = r1 * Math.cos(newAnglea) + pt.x; - nct1.y = r1 * Math.sin(newAnglea) + pt.y; - nct2.x = r2 * Math.cos(newAngleb) + pt.x; - nct2.y = r2 * Math.sin(newAngleb) + pt.y; + nct1.x = r1 * Math.cos(newAnglea) + pt.x + nct1.y = r1 * Math.sin(newAnglea) + pt.y + nct2.x = r2 * Math.cos(newAngleb) + pt.x + nct2.y = r2 * Math.sin(newAngleb) + pt.y - return [ nct1, nct2 ]; + return [nct1, nct2] } - return undefined; -}; + return undefined +} /** * @function module:path.getPath_ @@ -415,12 +414,12 @@ export const smoothControlPoints = (ct1, ct2, pt) => { * @returns {module:path.Path} */ export const getPath_ = (elem) => { - let p = pathData[elem.id]; + let p = pathData[elem.id] if (!p) { - p = pathData[elem.id] = new Path(elem); + p = pathData[elem.id] = new Path(elem) } - return p; -}; + return p +} /** * @function module:path.removePath_ @@ -428,34 +427,36 @@ export const getPath_ = (elem) => { * @returns {void} */ export const removePath_ = (id) => { - if (id in pathData) { delete pathData[id]; } -}; + if (id in pathData) { delete pathData[id] } +} -let newcx; let newcy; let oldcx; let oldcy; let angle; +let newcx; let newcy; let oldcx; let oldcy; let angle const getRotVals = (x, y) => { - let dx = x - oldcx; - let dy = y - oldcy; + let dx = x - oldcx + let dy = y - oldcy // rotate the point around the old center - 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; + 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 // now we want to rotate them around the new center in the reverse direction - dx -= newcx; - dy -= newcy; + dx -= newcx + dy -= newcy - r = Math.sqrt(dx * dx + dy * dy); - theta = Math.atan2(dy, dx) - angle; + r = Math.sqrt(dx * dx + dy * dy) + theta = Math.atan2(dy, dx) - angle - return { x: r * Math.cos(theta) + newcx, - y: r * Math.sin(theta) + newcy }; -}; + return { + x: r * Math.cos(theta) + newcx, + y: r * Math.sin(theta) + newcy + } +} // If the path was rotated, we must now pay the piper: // Every path point must be rotated into the rotated coordinate system of @@ -469,55 +470,55 @@ const getRotVals = (x, y) => { * @returns {void} */ export const recalcRotatedPath = () => { - const currentPath = path.elem; - angle = getRotationAngle(currentPath, true); - if (!angle) { return; } + const currentPath = path.elem + angle = getRotationAngle(currentPath, true) + if (!angle) { return } // selectedBBoxes[0] = path.oldbbox; - const oldbox = path.oldbbox; // selectedBBoxes[0], - oldcx = oldbox.x + oldbox.width / 2; - oldcy = oldbox.y + oldbox.height / 2; - const box = getBBox(currentPath); - newcx = box.x + box.width / 2; - newcy = box.y + box.height / 2; + const oldbox = path.oldbbox // selectedBBoxes[0], + oldcx = oldbox.x + oldbox.width / 2 + oldcy = oldbox.y + oldbox.height / 2 + 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 - const dx = newcx - oldcx; - const dy = newcy - oldcy; - const r = Math.sqrt(dx * dx + dy * dy); - const theta = Math.atan2(dy, dx) + angle; + const dx = newcx - oldcx + const dy = newcy - oldcy + const r = Math.sqrt(dx * dx + dy * dy) + const theta = Math.atan2(dy, dx) + angle - newcx = r * Math.cos(theta) + oldcx; - newcy = r * Math.sin(theta) + oldcy; + newcx = r * Math.cos(theta) + oldcx + newcy = r * Math.sin(theta) + oldcy - const list = currentPath.pathSegList; + const list = currentPath.pathSegList - let i = list.numberOfItems; + let i = list.numberOfItems while (i) { - i -= 1; - const seg = list.getItem(i); - const type = seg.pathSegType; - if (type === 1) { continue; } + i -= 1 + const seg = list.getItem(i) + const type = seg.pathSegType + if (type === 1) { continue } - const rvals = getRotVals(seg.x, seg.y); - const points = [ rvals.x, rvals.y ]; + const rvals = getRotVals(seg.x, seg.y) + const points = [rvals.x, rvals.y] if (!isNullish(seg.x1) && !isNullish(seg.x2)) { - 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); + 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) } - replacePathSeg(type, i, points); + replacePathSeg(type, i, points) } // loop for each point - /* box = */ getBBox(currentPath); + /* box = */ getBBox(currentPath) // selectedBBoxes[0].x = box.x; selectedBBoxes[0].y = box.y; // selectedBBoxes[0].width = box.width; selectedBBoxes[0].height = box.height; // now we must set the new transform to be rotated around the new center - const Rnc = svgCanvas.getSvgRoot().createSVGTransform(); - const tlist = currentPath.transform.baseVal; - Rnc.setRotate((angle * 180.0 / Math.PI), newcx, newcy); - tlist.replaceItem(Rnc, 0); -}; + const Rnc = svgCanvas.getSvgRoot().createSVGTransform() + const tlist = currentPath.transform.baseVal + Rnc.setRotate((angle * 180.0 / Math.PI), newcx, newcy) + tlist.replaceItem(Rnc, 0) +} // ==================================== // Public API starts here @@ -527,8 +528,8 @@ export const recalcRotatedPath = () => { * @returns {void} */ export const clearData = () => { - pathData = {}; -}; + pathData = {} +} // Making public for mocking /** @@ -538,27 +539,27 @@ export const clearData = () => { * @returns {void} */ export const reorientGrads = (elem, m) => { - const bb = utilsGetBBox(elem); + const bb = utilsGetBBox(elem) for (let i = 0; i < 2; i++) { - const type = i === 0 ? 'fill' : 'stroke'; - const attrVal = elem.getAttribute(type); + const type = i === 0 ? 'fill' : 'stroke' + const attrVal = elem.getAttribute(type) if (attrVal && attrVal.startsWith('url(')) { - const grad = getRefElem(attrVal); + const grad = getRefElem(attrVal) if (grad.tagName === 'linearGradient') { - let x1 = grad.getAttribute('x1') || 0; - let y1 = grad.getAttribute('y1') || 0; - let x2 = grad.getAttribute('x2') || 1; - let y2 = grad.getAttribute('y2') || 0; + 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; + 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 - const pt1 = transformPoint(x1, y1, m); - const pt2 = transformPoint(x2, y2, m); + const pt1 = transformPoint(x1, y1, m) + const pt2 = transformPoint(x2, y2, m) // Convert back to BB points const gCoords = { @@ -566,19 +567,19 @@ export const reorientGrads = (elem, m) => { y1: (pt1.y - bb.y) / bb.height, x2: (pt2.x - bb.x) / bb.width, y2: (pt2.y - bb.y) / bb.height - }; - - const newgrad = grad.cloneNode(true); - for (const [ key, value ] of Object.entries(gCoords)) { - newgrad.setAttribute(key, value); } - newgrad.id = svgCanvas.getNextId(); - findDefs().append(newgrad); - elem.setAttribute(type, 'url(#' + newgrad.id + ')'); + + const newgrad = grad.cloneNode(true) + for (const [key, value] of Object.entries(gCoords)) { + newgrad.setAttribute(key, value) + } + newgrad.id = svgCanvas.getNextId() + findDefs().append(newgrad) + elem.setAttribute(type, 'url(#' + newgrad.id + ')') } } } -}; +} /** * This is how we map paths to our preferred relative segment types. @@ -588,7 +589,7 @@ export const reorientGrads = (elem, m) => { 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. @@ -599,159 +600,159 @@ const pathMap = [ * @returns {string} */ export const convertPath = (pth, toRel) => { - const { pathSegList } = pth; - const len = pathSegList.numberOfItems; - let curx = 0; let cury = 0; - let d = ''; - let lastM = null; + const { pathSegList } = pth + const len = pathSegList.numberOfItems + let curx = 0; let cury = 0 + let d = '' + let lastM = null for (let i = 0; i < len; ++i) { - const seg = pathSegList.getItem(i); + const seg = pathSegList.getItem(i) // if these properties are not in the segment, set them to zero - let x = seg.x || 0; - let y = seg.y || 0; - let x1 = seg.x1 || 0; - let y1 = seg.y1 || 0; - let x2 = seg.x2 || 0; - let y2 = seg.y2 || 0; + let x = seg.x || 0 + let y = seg.y || 0 + let x1 = seg.x1 || 0 + let y1 = seg.y1 || 0 + let x2 = seg.x2 || 0 + let y2 = seg.y2 || 0 - const type = seg.pathSegType; - let letter = pathMap[type][toRel ? 'toLowerCase' : 'toUpperCase'](); + const type = seg.pathSegType + let letter = pathMap[type][toRel ? 'toLowerCase' : 'toUpperCase']() switch (type) { - case 1: // z,Z closepath (Z/z) - d += 'z'; - if (lastM && !toRel) { - curx = lastM[0]; - cury = lastM[1]; - } - break; - case 12: // absolute horizontal line (H) - x -= curx; + case 1: // z,Z closepath (Z/z) + d += 'z' + if (lastM && !toRel) { + curx = lastM[0] + cury = lastM[1] + } + break + case 12: // absolute horizontal line (H) + x -= curx // Fallthrough - case 13: // relative horizontal line (h) - if (toRel) { - y = 0; - curx += x; - letter = 'l'; - } else { - y = cury; - x += curx; - curx = x; - letter = 'L'; - } - // Convert to "line" for easier editing - d += pathDSegment(letter, [ [ x, y ] ]); - break; - case 14: // absolute vertical line (V) - y -= cury; + case 13: // relative horizontal line (h) + if (toRel) { + y = 0 + curx += x + letter = 'l' + } else { + y = cury + x += curx + curx = x + letter = 'L' + } + // Convert to "line" for easier editing + d += pathDSegment(letter, [[x, y]]) + break + case 14: // absolute vertical line (V) + y -= cury // Fallthrough - case 15: // relative vertical line (v) - if (toRel) { - x = 0; - cury += y; - letter = 'l'; - } else { - x = curx; - y += cury; - cury = y; - letter = 'L'; - } - // Convert to "line" for easier editing - d += pathDSegment(letter, [ [ x, y ] ]); - break; - case 2: // absolute move (M) - case 4: // absolute line (L) - case 18: // absolute smooth quad (T) - case 10: // absolute elliptical arc (A) - x -= curx; - y -= cury; + case 15: // relative vertical line (v) + if (toRel) { + x = 0 + cury += y + letter = 'l' + } else { + x = curx + y += cury + cury = y + letter = 'L' + } + // Convert to "line" for easier editing + d += pathDSegment(letter, [[x, y]]) + break + case 2: // absolute move (M) + case 4: // absolute line (L) + case 18: // absolute smooth quad (T) + case 10: // absolute elliptical arc (A) + x -= curx + y -= cury // Fallthrough - case 5: // relative line (l) - case 3: // relative move (m) - case 19: // relative smooth quad (t) - if (toRel) { - curx += x; - cury += y; - } else { - x += curx; - y += cury; - curx = x; - cury = y; - } - if (type === 2 || type === 3) { lastM = [ curx, cury ]; } + case 5: // relative line (l) + case 3: // relative move (m) + case 19: // relative smooth quad (t) + if (toRel) { + curx += x + cury += y + } else { + x += curx + y += cury + curx = x + cury = y + } + if (type === 2 || type === 3) { lastM = [curx, cury] } - d += pathDSegment(letter, [ [ x, y ] ]); - break; - case 6: // absolute cubic (C) - x -= curx; x1 -= curx; x2 -= curx; - y -= cury; y1 -= cury; y2 -= cury; + d += pathDSegment(letter, [[x, y]]) + break + case 6: // absolute cubic (C) + x -= curx; x1 -= curx; x2 -= curx + y -= cury; y1 -= cury; y2 -= cury // Fallthrough - case 7: // relative cubic (c) - if (toRel) { - curx += x; - cury += y; - } else { - x += curx; x1 += curx; x2 += curx; - y += cury; y1 += cury; y2 += cury; - curx = x; - cury = y; - } - d += pathDSegment(letter, [ [ x1, y1 ], [ x2, y2 ], [ x, y ] ]); - break; - case 8: // absolute quad (Q) - x -= curx; x1 -= curx; - y -= cury; y1 -= cury; + case 7: // relative cubic (c) + if (toRel) { + curx += x + cury += y + } else { + x += curx; x1 += curx; x2 += curx + y += cury; y1 += cury; y2 += cury + curx = x + cury = y + } + d += pathDSegment(letter, [[x1, y1], [x2, y2], [x, y]]) + break + case 8: // absolute quad (Q) + x -= curx; x1 -= curx + y -= cury; y1 -= cury // Fallthrough - case 9: // relative quad (q) - if (toRel) { - curx += x; - cury += y; - } else { - x += curx; x1 += curx; - y += cury; y1 += cury; - curx = x; - cury = y; - } - d += pathDSegment(letter, [ [ x1, y1 ], [ x, y ] ]); - break; + case 9: // relative quad (q) + if (toRel) { + curx += x + cury += y + } else { + x += curx; x1 += curx + y += cury; y1 += cury + curx = x + cury = y + } + d += pathDSegment(letter, [[x1, y1], [x, y]]) + break // Fallthrough - case 11: // relative elliptical arc (a) - if (toRel) { - curx += x; - cury += y; - } else { - x += curx; - y += cury; - curx = x; - cury = y; - } - d += pathDSegment(letter, [ [ seg.r1, seg.r2 ] ], [ - seg.angle, - (seg.largeArcFlag ? 1 : 0), - (seg.sweepFlag ? 1 : 0) - ], [ x, y ]); - break; - case 16: // absolute smooth cubic (S) - x -= curx; x2 -= curx; - y -= cury; y2 -= cury; + case 11: // relative elliptical arc (a) + if (toRel) { + curx += x + cury += y + } else { + x += curx + y += cury + curx = x + cury = y + } + d += pathDSegment(letter, [[seg.r1, seg.r2]], [ + seg.angle, + (seg.largeArcFlag ? 1 : 0), + (seg.sweepFlag ? 1 : 0) + ], [x, y]) + break + case 16: // absolute smooth cubic (S) + x -= curx; x2 -= curx + y -= cury; y2 -= cury // Fallthrough - case 17: // relative smooth cubic (s) - if (toRel) { - curx += x; - cury += y; - } else { - x += curx; x2 += curx; - y += cury; y2 += cury; - curx = x; - cury = y; - } - d += pathDSegment(letter, [ [ x2, y2 ], [ x, y ] ]); - break; + case 17: // relative smooth cubic (s) + if (toRel) { + curx += x + cury += y + } else { + x += curx; x2 += curx + y += cury; y2 += cury + curx = x + cury = y + } + d += pathDSegment(letter, [[x2, y2], [x, y]]) + break } // switch on path segment type } // for each segment - return d; -}; + return d +} /** * TODO: refactor callers in `convertPath` to use `getPathDFromSegments` instead of this function. @@ -764,21 +765,21 @@ export const convertPath = (pth, toRel) => { */ const pathDSegment = (letter, points, morePoints, lastPoint) => { points.forEach((pnt, i) => { - points[i] = shortFloat(pnt); - }); - let segment = letter + points.join(' '); + points[i] = shortFloat(pnt) + }) + let segment = letter + points.join(' ') if (morePoints) { - segment += ' ' + morePoints.join(' '); + segment += ' ' + morePoints.join(' ') } if (lastPoint) { - segment += ' ' + shortFloat(lastPoint); + segment += ' ' + shortFloat(lastPoint) } - return segment; -}; + return segment +} /** * Group: Path edit functions. * Functions relating to editing path elements. */ -export const pathActions = pathActionsMethod; +export const pathActions = pathActionsMethod // end pathActions diff --git a/src/svgcanvas/recalculate.js b/src/svgcanvas/recalculate.js index 2cc8087d..93cac384 100644 --- a/src/svgcanvas/recalculate.js +++ b/src/svgcanvas/recalculate.js @@ -4,21 +4,21 @@ * @license MIT */ -import { NS } from './namespaces.js'; -import { convertToNum } from '../common/units.js'; -import { isWebkit } from '../common/browser.js'; -import { getRotationAngle, getHref, getBBox, getRefElem, isNullish } from './utilities.js'; -import { BatchCommand, ChangeElementCommand } from './history.js'; -import { remapElement } from './coords.js'; +import { NS } from './namespaces.js' +import { convertToNum } from '../common/units.js' +import { isWebkit } from '../common/browser.js' +import { getRotationAngle, getHref, getBBox, getRefElem, isNullish } from './utilities.js' +import { BatchCommand, ChangeElementCommand } from './history.js' +import { remapElement } from './coords.js' import { isIdentity, matrixMultiply, transformPoint, transformListToTransform, hasMatrixTransform -} from './math.js'; +} from './math.js' import { mergeDeep -} from '../editor/components/jgraduate/Util.js'; +} from '../editor/components/jgraduate/Util.js' -let svgCanvas; +let svgCanvas /** * @interface module:recalculate.EditorContext @@ -43,8 +43,8 @@ let svgCanvas; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; -}; + svgCanvas = canvas +} /** * Updates a ``s values based on the given translation of an element. @@ -55,16 +55,16 @@ export const init = function (canvas) { * @returns {void} */ export const updateClipPath = function (attr, tx, ty) { - const path = getRefElem(attr).firstChild; - const cpXform = path.transform.baseVal; - const newxlate = svgCanvas.getSvgRoot().createSVGTransform(); - newxlate.setTranslate(tx, ty); + const path = getRefElem(attr).firstChild + const cpXform = path.transform.baseVal + const newxlate = svgCanvas.getSvgRoot().createSVGTransform() + newxlate.setTranslate(tx, ty) - cpXform.appendItem(newxlate); + cpXform.appendItem(newxlate) // Update clipPath's dimensions - recalculateDimensions(path); -}; + recalculateDimensions(path) +} /** * Decides the course of action based on the element's transform list. @@ -73,18 +73,18 @@ export const updateClipPath = function (attr, tx, ty) { * @returns {Command} Undo command object with the resulting change */ export const recalculateDimensions = function (selected) { - if (!selected) return null; - const svgroot = svgCanvas.getSvgRoot(); - const dataStorage = svgCanvas.getDataStorage(); - const tlist = selected.transform?.baseVal; + if (!selected) return null + const svgroot = svgCanvas.getSvgRoot() + const dataStorage = svgCanvas.getDataStorage() + const tlist = selected.transform?.baseVal // remove any unnecessary transforms if (tlist && tlist.numberOfItems > 0) { - let k = tlist.numberOfItems; - const noi = k; + let k = tlist.numberOfItems + const noi = k while (k--) { - const xform = tlist.getItem(k); + const xform = tlist.getItem(k) if (xform.type === 0) { - tlist.removeItem(k); + tlist.removeItem(k) // remove identity matrices } else if (xform.type === 1) { if (isIdentity(xform.matrix)) { @@ -93,218 +93,218 @@ export const recalculateDimensions = function (selected) { // `removeItem` preventing `removeAttribute` from // subsequently working // See https://bugs.chromium.org/p/chromium/issues/detail?id=843901 - selected.removeAttribute('transform'); - return null; + selected.removeAttribute('transform') + return null } - tlist.removeItem(k); + tlist.removeItem(k) } // remove zero-degree rotations } else if (xform.type === 4 && xform.angle === 0) { - tlist.removeItem(k); + tlist.removeItem(k) } } // End here if all it has is a rotation if (tlist.numberOfItems === 1 && - getRotationAngle(selected)) { return null; } + getRotationAngle(selected)) { return null } } // if this element had no transforms, we are done if (!tlist || tlist.numberOfItems === 0) { // Chrome apparently had a bug that requires clearing the attribute first. - selected.setAttribute('transform', ''); + selected.setAttribute('transform', '') // However, this still next line currently doesn't work at all in Chrome - selected.removeAttribute('transform'); + selected.removeAttribute('transform') // selected.transform.baseVal.clear(); // Didn't help for Chrome bug - return null; + return null } // TODO: Make this work for more than 2 if (tlist) { - let mxs = []; - let k = tlist.numberOfItems; + let mxs = [] + let k = tlist.numberOfItems while (k--) { - const xform = tlist.getItem(k); + const xform = tlist.getItem(k) if (xform.type === 1) { - mxs.push([ xform.matrix, k ]); + mxs.push([xform.matrix, k]) } else if (mxs.length) { - mxs = []; + mxs = [] } } if (mxs.length === 2) { - 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]); + 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) { - const mt = svgroot.createSVGTransform(); + 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.appendItem(mt); + ) + mt.setMatrix(m) + 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). switch (selected.tagName) { // Ignore these elements, as they can absorb the [M] - case 'line': - case 'polyline': - case 'polygon': - case 'path': - break; - default: - if ((tlist.numberOfItems === 1 && tlist.getItem(0).type === 1) || + case 'line': + case 'polyline': + case 'polygon': + case 'path': + break + default: + if ((tlist.numberOfItems === 1 && tlist.getItem(0).type === 1) || (tlist.numberOfItems === 2 && tlist.getItem(0).type === 1 && tlist.getItem(0).type === 4)) { - return null; - } + return null + } } // Grouped SVG element - const gsvg = (dataStorage.has(selected, 'gsvg')) ? dataStorage.get(selected, 'gsvg') : undefined; + const gsvg = (dataStorage.has(selected, 'gsvg')) ? dataStorage.get(selected, 'gsvg') : undefined // we know we have some transforms, so set up return variable - const batchCmd = new BatchCommand('Transform'); + const batchCmd = new BatchCommand('Transform') // store initial values that will be affected by reducing the transform list - let changes = {}; - let initial = null; - let attrs = []; + let changes = {} + let initial = null + let attrs = [] switch (selected.tagName) { - case 'line': - attrs = [ 'x1', 'y1', 'x2', 'y2' ]; - break; - case 'circle': - attrs = [ 'cx', 'cy', 'r' ]; - break; - case 'ellipse': - attrs = [ 'cx', 'cy', 'rx', 'ry' ]; - break; - case 'foreignObject': - case 'rect': - case 'image': - attrs = [ 'width', 'height', 'x', 'y' ]; - break; - case 'use': - case 'text': - case 'tspan': - attrs = [ 'x', 'y' ]; - break; - case 'polygon': - case 'polyline': { - initial = {}; - initial.points = selected.getAttribute('points'); - const list = selected.points; - const len = list.numberOfItems; - changes.points = new Array(len); - for (let i = 0; i < len; ++i) { - const pt = list.getItem(i); - changes.points[i] = { x: pt.x, y: pt.y }; - } - break; - } case 'path': - initial = {}; - initial.d = selected.getAttribute('d'); - changes.d = selected.getAttribute('d'); - break; + case 'line': + attrs = ['x1', 'y1', 'x2', 'y2'] + break + case 'circle': + attrs = ['cx', 'cy', 'r'] + break + case 'ellipse': + attrs = ['cx', 'cy', 'rx', 'ry'] + break + case 'foreignObject': + case 'rect': + case 'image': + attrs = ['width', 'height', 'x', 'y'] + break + case 'use': + case 'text': + case 'tspan': + attrs = ['x', 'y'] + break + case 'polygon': + case 'polyline': { + initial = {} + initial.points = selected.getAttribute('points') + const list = selected.points + const len = list.numberOfItems + changes.points = new Array(len) + for (let i = 0; i < len; ++i) { + const pt = list.getItem(i) + changes.points[i] = { x: pt.x, y: pt.y } + } + break + } case 'path': + initial = {} + initial.d = selected.getAttribute('d') + changes.d = selected.getAttribute('d') + break } // switch on element type to get initial values if (attrs.length) { Array.prototype.forEach.call(attrs, function (attr) { - changes[attr] = selected.getAttribute(attr); - }); - for (const [ attr, val ] of Object.entries(changes)) { - changes[attr] = convertToNum(attr, val); + changes[attr] = selected.getAttribute(attr) + }) + for (const [attr, val] of Object.entries(changes)) { + changes[attr] = convertToNum(attr, val) } } else if (gsvg) { // GSVG exception changes = { x: Number(gsvg.getAttribute('x')) || 0, y: Number(gsvg.getAttribute('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 = mergeDeep({}, changes); - for (const [ attr, val ] of Object.entries(initial)) { - initial[attr] = convertToNum(attr, val); + initial = mergeDeep({}, changes) + for (const [attr, val] of Object.entries(initial)) { + initial[attr] = convertToNum(attr, val) } } // save the start transform value too - initial.transform = svgCanvas.getStartTransform() || ''; + initial.transform = svgCanvas.getStartTransform() || '' - let oldcenter; let newcenter; + let oldcenter; let newcenter // if it's a regular group, we have special processing to flatten transforms if ((selected.tagName === 'g' && !gsvg) || selected.tagName === 'a') { - const box = getBBox(selected); + const box = getBBox(selected) - oldcenter = { x: box.x + box.width / 2, y: box.y + box.height / 2 }; + oldcenter = { 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 - ); + ) // let m = svgroot.createSVGMatrix(); // temporarily strip off the rotate and save the old center - const gangle = getRotationAngle(selected); + const gangle = getRotationAngle(selected) if (gangle) { - const a = gangle * Math.PI / 180; - const s = Math.abs(a) > (1.0e-10) ? Math.sin(a) / (1 - Math.cos(a)) : 2 / a; + const a = gangle * Math.PI / 180 + const s = Math.abs(a) > (1.0e-10) ? Math.sin(a) / (1 - Math.cos(a)) : 2 / a for (let i = 0; i < tlist.numberOfItems; ++i) { - const xform = tlist.getItem(i); + const xform = tlist.getItem(i) if (xform.type === 4) { // extract old center through mystical arts - const rm = xform.matrix; - oldcenter.y = (s * rm.e + rm.f) / 2; - oldcenter.x = (rm.e - s * rm.f) / 2; - tlist.removeItem(i); - break; + const rm = xform.matrix + oldcenter.y = (s * rm.e + rm.f) / 2 + oldcenter.x = (rm.e - s * rm.f) / 2 + tlist.removeItem(i) + break } } } - const N = tlist.numberOfItems; - let tx = 0; let ty = 0; let operation = 0; + const N = tlist.numberOfItems + let tx = 0; let ty = 0; let operation = 0 - let firstM; + let firstM if (N) { - firstM = tlist.getItem(0).matrix; + firstM = tlist.getItem(0).matrix } - let oldStartTransform; + 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 + operation = 3 // scale // if the children are unrotated, pass the scale down directly // otherwise pass the equivalent matrix() down directly - const tm = tlist.getItem(N - 3).matrix; - const sm = tlist.getItem(N - 2).matrix; - const tmn = tlist.getItem(N - 1).matrix; + const tm = tlist.getItem(N - 3).matrix + const sm = tlist.getItem(N - 2).matrix + const tmn = tlist.getItem(N - 1).matrix - const children = selected.childNodes; - let c = children.length; + const children = selected.childNodes + let c = children.length while (c--) { - const child = children.item(c); - tx = 0; - ty = 0; + const child = children.item(c) + tx = 0 + ty = 0 if (child.nodeType === 1) { - const childTlist = child.transform.baseVal; + const childTlist = child.transform.baseVal // some children might not have a transform (, , etc) - if (!childTlist) { continue; } + if (!childTlist) { continue } - const m = transformListToTransform(childTlist).matrix; + const m = transformListToTransform(childTlist).matrix // Convert a matrix to a scale if applicable // if (hasMatrixTransform(childTlist) && childTlist.numberOfItems == 1) { @@ -322,15 +322,15 @@ export const recalculateDimensions = function (selected) { // } // } - const angle = getRotationAngle(child); - oldStartTransform = svgCanvas.getStartTransform(); + const angle = getRotationAngle(child) + oldStartTransform = svgCanvas.getStartTransform() // const childxforms = []; - svgCanvas.setStartTransform(child.getAttribute('transform')); + svgCanvas.setStartTransform(child.getAttribute('transform')) if (angle || hasMatrixTransform(childTlist)) { - const e2t = svgroot.createSVGTransform(); - e2t.setMatrix(matrixMultiply(tm, sm, tmn, m)); - childTlist.clear(); - childTlist.appendItem(e2t); + 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 } else { @@ -342,159 +342,159 @@ export const recalculateDimensions = function (selected) { // (only bringing [-T] to the right of [M]) // [T][S][-T][M] = [T][S][M][-T2] // [-T2] = [M_inv][-T][M] - const t2n = matrixMultiply(m.inverse(), tmn, m); + const t2n = matrixMultiply(m.inverse(), tmn, m) // [T2] is always negative translation of [-T2] - const t2 = svgroot.createSVGMatrix(); - t2.e = -t2n.e; - t2.f = -t2n.f; + 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] - const s2 = matrixMultiply(t2.inverse(), m.inverse(), tm, sm, tmn, m, t2n.inverse()); + const s2 = matrixMultiply(t2.inverse(), m.inverse(), tm, sm, tmn, m, t2n.inverse()) - const translateOrigin = svgroot.createSVGTransform(); - const scale = svgroot.createSVGTransform(); - const translateBack = svgroot.createSVGTransform(); - translateOrigin.setTranslate(t2n.e, t2n.f); - scale.setScale(s2.a, s2.d); - translateBack.setTranslate(t2.e, t2.f); - childTlist.appendItem(translateBack); - childTlist.appendItem(scale); - childTlist.appendItem(translateOrigin); + const translateOrigin = svgroot.createSVGTransform() + const scale = svgroot.createSVGTransform() + const translateBack = svgroot.createSVGTransform() + translateOrigin.setTranslate(t2n.e, t2n.f) + scale.setScale(s2.a, s2.d) + translateBack.setTranslate(t2.e, t2.f) + childTlist.appendItem(translateBack) + childTlist.appendItem(scale) + childTlist.appendItem(translateOrigin) } // not rotated - batchCmd.addSubCommand(recalculateDimensions(child)); - svgCanvas.setStartTransform(oldStartTransform); + batchCmd.addSubCommand(recalculateDimensions(child)) + svgCanvas.setStartTransform(oldStartTransform) } // element } // for each child // Remove these transforms from group - tlist.removeItem(N - 1); - tlist.removeItem(N - 2); - tlist.removeItem(N - 3); + tlist.removeItem(N - 1) + tlist.removeItem(N - 2) + tlist.removeItem(N - 3) } else if (N >= 3 && tlist.getItem(N - 1).type === 1) { - operation = 3; // scale - const m = transformListToTransform(tlist).matrix; - const e2t = svgroot.createSVGTransform(); - e2t.setMatrix(m); - tlist.clear(); - tlist.appendItem(e2t); + operation = 3 // scale + 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 // 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 - const T_M = transformListToTransform(tlist).matrix; - tlist.removeItem(0); - const mInv = transformListToTransform(tlist).matrix.inverse(); - const M2 = matrixMultiply(mInv, T_M); + operation = 2 // translate + const T_M = transformListToTransform(tlist).matrix + tlist.removeItem(0) + const mInv = transformListToTransform(tlist).matrix.inverse() + const M2 = matrixMultiply(mInv, T_M) - tx = M2.e; - ty = M2.f; + tx = M2.e + ty = M2.f if (tx !== 0 || ty !== 0) { // we pass the translates down to the individual children - const children = selected.childNodes; - let c = children.length; + const children = selected.childNodes + let c = children.length - const clipPathsDone = []; + const clipPathsDone = [] while (c--) { - const child = children.item(c); + const child = children.item(c) if (child.nodeType === 1) { // Check if child has clip-path if (child.getAttribute('clip-path')) { // tx, ty - const attr = child.getAttribute('clip-path'); + const attr = child.getAttribute('clip-path') if (!clipPathsDone.includes(attr)) { - updateClipPath(attr, tx, ty); - clipPathsDone.push(attr); + updateClipPath(attr, tx, ty) + clipPathsDone.push(attr) } } - oldStartTransform = svgCanvas.getStartTransform(); - svgCanvas.setStartTransform(child.getAttribute('transform')); + oldStartTransform = svgCanvas.getStartTransform() + svgCanvas.setStartTransform(child.getAttribute('transform')) - const childTlist = child.transform?.baseVal; + const childTlist = child.transform?.baseVal // some children might not have a transform (, , etc) if (childTlist) { - const newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx, ty); + const newxlate = svgroot.createSVGTransform() + newxlate.setTranslate(tx, ty) if (childTlist.numberOfItems) { - childTlist.insertItemBefore(newxlate, 0); + childTlist.insertItemBefore(newxlate, 0) } else { - childTlist.appendItem(newxlate); + childTlist.appendItem(newxlate) } - batchCmd.addSubCommand(recalculateDimensions(child)); + batchCmd.addSubCommand(recalculateDimensions(child)) // If any 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 - const uses = selected.getElementsByTagNameNS(NS.SVG, 'use'); - const href = '#' + child.id; - let u = uses.length; + const uses = selected.getElementsByTagNameNS(NS.SVG, 'use') + const href = '#' + child.id + let u = uses.length while (u--) { - const useElem = uses.item(u); + const useElem = uses.item(u) if (href === getHref(useElem)) { - const usexlate = svgroot.createSVGTransform(); - usexlate.setTranslate(-tx, -ty); - useElem.transform.baseVal.insertItemBefore(usexlate, 0); - batchCmd.addSubCommand(recalculateDimensions(useElem)); + const usexlate = svgroot.createSVGTransform() + usexlate.setTranslate(-tx, -ty) + useElem.transform.baseVal.insertItemBefore(usexlate, 0) + batchCmd.addSubCommand(recalculateDimensions(useElem)) } } - svgCanvas.setStartTransform(oldStartTransform); + svgCanvas.setStartTransform(oldStartTransform) } } } - svgCanvas.setStartTransform(oldStartTransform); + svgCanvas.setStartTransform(oldStartTransform) } // else, a matrix imposition from a parent group // keep pushing it down to the children } else if (N === 1 && tlist.getItem(0).type === 1 && !gangle) { - operation = 1; - const m = tlist.getItem(0).matrix; - const children = selected.childNodes; - let c = children.length; + operation = 1 + const m = tlist.getItem(0).matrix + const children = selected.childNodes + let c = children.length while (c--) { - const child = children.item(c); + const child = children.item(c) if (child.nodeType === 1) { - oldStartTransform = svgCanvas.getStartTransform(); - svgCanvas.setStartTransform(child.getAttribute('transform')); - const childTlist = child.transform?.baseVal; + oldStartTransform = svgCanvas.getStartTransform() + svgCanvas.setStartTransform(child.getAttribute('transform')) + const childTlist = child.transform?.baseVal - if (!childTlist) { continue; } + if (!childTlist) { continue } - const em = matrixMultiply(m, transformListToTransform(childTlist).matrix); - const e2m = svgroot.createSVGTransform(); - e2m.setMatrix(em); - childTlist.clear(); - childTlist.appendItem(e2m, 0); + const em = matrixMultiply(m, transformListToTransform(childTlist).matrix) + const e2m = svgroot.createSVGTransform() + e2m.setMatrix(em) + childTlist.clear() + childTlist.appendItem(e2m, 0) - batchCmd.addSubCommand(recalculateDimensions(child)); - svgCanvas.setStartTransform(oldStartTransform); + batchCmd.addSubCommand(recalculateDimensions(child)) + svgCanvas.setStartTransform(oldStartTransform) // Convert stroke // TODO: Find out if this should actually happen somewhere else - const sw = child.getAttribute('stroke-width'); + const sw = child.getAttribute('stroke-width') if (child.getAttribute('stroke') !== 'none' && !isNaN(sw)) { - const avg = (Math.abs(em.a) + Math.abs(em.d)) / 2; - child.setAttribute('stroke-width', sw * avg); + const avg = (Math.abs(em.a) + Math.abs(em.d)) / 2 + child.setAttribute('stroke-width', sw * avg) } } } - tlist.clear(); + tlist.clear() // else it was just a rotate } else { if (gangle) { - const 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 (tlist.numberOfItems === 0) { - selected.removeAttribute('transform'); + selected.removeAttribute('transform') } - return null; + return null } // if it was a translate, put back the rotate at the new center @@ -503,129 +503,129 @@ export const recalculateDimensions = function (selected) { newcenter = { x: oldcenter.x + firstM.e, y: oldcenter.y + firstM.f - }; + } - const 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) { - const m = transformListToTransform(tlist).matrix; - const roldt = svgroot.createSVGTransform(); - roldt.setRotate(gangle, oldcenter.x, oldcenter.y); - const rold = roldt.matrix; - const rnew = svgroot.createSVGTransform(); - rnew.setRotate(gangle, newcenter.x, newcenter.y); - const rnewInv = rnew.matrix.inverse(); - const mInv = m.inverse(); - const extrat = matrixMultiply(mInv, rnewInv, rold, m); + const m = transformListToTransform(tlist).matrix + const roldt = svgroot.createSVGTransform() + roldt.setRotate(gangle, oldcenter.x, oldcenter.y) + const rold = roldt.matrix + const rnew = svgroot.createSVGTransform() + rnew.setRotate(gangle, newcenter.x, newcenter.y) + const rnewInv = rnew.matrix.inverse() + const mInv = m.inverse() + const extrat = matrixMultiply(mInv, rnewInv, rold, m) - tx = extrat.e; - ty = extrat.f; + 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 - const children = selected.childNodes; - let c = children.length; + const children = selected.childNodes + let c = children.length while (c--) { - const child = children.item(c); + const child = children.item(c) if (child.nodeType === 1) { - oldStartTransform = svgCanvas.getStartTransform(); - svgCanvas.setStartTransform(child.getAttribute('transform')); - const childTlist = child.transform?.baseVal; - const newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx, ty); + oldStartTransform = svgCanvas.getStartTransform() + svgCanvas.setStartTransform(child.getAttribute('transform')) + const childTlist = child.transform?.baseVal + const newxlate = svgroot.createSVGTransform() + newxlate.setTranslate(tx, ty) if (childTlist.numberOfItems) { - childTlist.insertItemBefore(newxlate, 0); + childTlist.insertItemBefore(newxlate, 0) } else { - childTlist.appendItem(newxlate); + childTlist.appendItem(newxlate) } - batchCmd.addSubCommand(recalculateDimensions(child)); - svgCanvas.setStartTransform(oldStartTransform); + batchCmd.addSubCommand(recalculateDimensions(child)) + svgCanvas.setStartTransform(oldStartTransform) } } } if (gangle) { if (tlist.numberOfItems) { - tlist.insertItemBefore(rnew, 0); + tlist.insertItemBefore(rnew, 0) } else { - tlist.appendItem(rnew); + tlist.appendItem(rnew) } } } // else, it's a non-group } else { // TODO: box might be null for some elements ( etc), need to handle this - const box = getBBox(selected); + const box = getBBox(selected) // Paths (and possbly other shapes) will have no BBox while still in , // 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; + if (!box && selected.tagName !== 'path') return null - let m; // = svgroot.createSVGMatrix(); + let m // = svgroot.createSVGMatrix(); // temporarily strip off the rotate and save the old center - const angle = getRotationAngle(selected); + const angle = getRotationAngle(selected) if (angle) { - oldcenter = { x: box.x + box.width / 2, y: box.y + box.height / 2 }; + oldcenter = { 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 - ); + ) - const a = angle * Math.PI / 180; + 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; + : 2 / a for (let i = 0; i < tlist.numberOfItems; ++i) { - const xform = tlist.getItem(i); + const xform = tlist.getItem(i) if (xform.type === 4) { // extract old center through mystical arts - const rm = xform.matrix; - oldcenter.y = (s * rm.e + rm.f) / 2; - oldcenter.x = (rm.e - s * rm.f) / 2; - tlist.removeItem(i); - break; + 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 - let operation = 0; - const N = tlist.numberOfItems; + 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()) { - const fill = selected.getAttribute('fill'); + const fill = selected.getAttribute('fill') if (fill && fill.startsWith('url(')) { - const paint = getRefElem(fill); + const paint = getRefElem(fill) if (paint) { - let type = 'pattern'; - if (paint?.tagName !== type) type = 'gradient'; - const attrVal = paint.getAttribute(type + 'Units'); + let type = 'pattern' + if (paint?.tagName !== type) type = 'gradient' + const attrVal = paint.getAttribute(type + 'Units') if (attrVal === 'userSpaceOnUse') { // Update the userSpaceOnUse element - m = transformListToTransform(tlist).matrix; - const gtlist = paint.transform.baseVal; - 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); + m = transformListToTransform(tlist).matrix + const gtlist = paint.transform.baseVal + 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) } } } @@ -640,92 +640,92 @@ export const recalculateDimensions = function (selected) { // Removed this so a with a given [T][S][T] would convert to a matrix. // Is that bad? // && selected.nodeName != 'use' - operation = 3; // scale - m = transformListToTransform(tlist, N - 3, N - 1).matrix; - tlist.removeItem(N - 1); - tlist.removeItem(N - 2); - tlist.removeItem(N - 3); + operation = 3 // scale + 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 - m = transformListToTransform(tlist).matrix; - const e2t = svgroot.createSVGTransform(); - e2t.setMatrix(m); - tlist.clear(); - tlist.appendItem(e2t); + operation = 3 // scale + m = transformListToTransform(tlist).matrix + const e2t = svgroot.createSVGTransform() + e2t.setMatrix(m) + tlist.clear() + tlist.appendItem(e2t) // reset the matrix so that the element is not re-mapped - m = svgroot.createSVGMatrix(); + 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 - const oldxlate = tlist.getItem(0).matrix; - const meq = transformListToTransform(tlist, 1).matrix; - const meqInv = meq.inverse(); - m = matrixMultiply(meqInv, oldxlate, meq); - tlist.removeItem(0); + operation = 2 // translate + const oldxlate = tlist.getItem(0).matrix + const meq = transformListToTransform(tlist, 1).matrix + const 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) { // Remap all point-based elements - m = transformListToTransform(tlist).matrix; + m = transformListToTransform(tlist).matrix switch (selected.tagName) { - case 'line': - changes = { - x1: selected.getAttribute('x1'), - y1: selected.getAttribute('y1'), - x2: selected.getAttribute('x2'), - y2: selected.getAttribute('y2') - }; - // Fallthrough - case 'polyline': - case 'polygon': - changes.points = selected.getAttribute('points'); - if (changes.points) { - const list = selected.points; - const len = list.numberOfItems; - changes.points = new Array(len); - for (let i = 0; i < len; ++i) { - const pt = list.getItem(i); - changes.points[i] = { x: pt.x, y: pt.y }; + case 'line': + changes = { + x1: selected.getAttribute('x1'), + y1: selected.getAttribute('y1'), + x2: selected.getAttribute('x2'), + y2: selected.getAttribute('y2') } - } // Fallthrough - case 'path': - changes.d = selected.getAttribute('d'); - operation = 1; - tlist.clear(); - break; - default: - break; + case 'polyline': + case 'polygon': + changes.points = selected.getAttribute('points') + if (changes.points) { + const list = selected.points + const len = list.numberOfItems + changes.points = new Array(len) + for (let i = 0; i < len; ++i) { + const pt = list.getItem(i) + changes.points[i] = { x: pt.x, y: pt.y } + } + } + // Fallthrough + case 'path': + changes.d = selected.getAttribute('d') + operation = 1 + tlist.clear() + break + default: + break } // if it was a rotation, put the rotate back and return without a command // (this function has zero work to do for a rotate()) } else { // operation = 4; // rotation if (angle) { - const newRot = svgroot.createSVGTransform(); - newRot.setRotate(angle, newcenter.x, newcenter.y); + const newRot = svgroot.createSVGTransform() + newRot.setRotate(angle, newcenter.x, newcenter.y) if (tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); + tlist.insertItemBefore(newRot, 0) } else { - tlist.appendItem(newRot); + tlist.appendItem(newRot) } } if (tlist.numberOfItems === 0) { - selected.removeAttribute('transform'); + selected.removeAttribute('transform') } - return null; + return null } // 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, m); + remapElement(selected, changes, m) } // if we are remapping // if it was a translate, put back the rotate at the new center @@ -735,30 +735,30 @@ export const recalculateDimensions = function (selected) { newcenter = { x: oldcenter.x + m.e, y: oldcenter.y + m.f - }; + } } - const newRot = svgroot.createSVGTransform(); - newRot.setRotate(angle, newcenter.x, newcenter.y); + const newRot = svgroot.createSVGTransform() + newRot.setRotate(angle, newcenter.x, newcenter.y) if (tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); + tlist.insertItemBefore(newRot, 0) } else { - tlist.appendItem(newRot); + 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, // on a text element, also translate any tspan children. if (selected.tagName === 'text') { - const children = selected.childNodes; - let c = children.length; + const children = selected.childNodes + let c = children.length while (c--) { - const child = children.item(c); + const child = children.item(c) if (child.tagName === 'tspan') { const tspanChanges = { x: Number(child.getAttribute('x')) || 0, y: Number(child.getAttribute('y')) || 0 - }; - remapElement(child, tspanChanges, m); + } + remapElement(child, tspanChanges, m) } } } @@ -767,22 +767,22 @@ export const recalculateDimensions = function (selected) { // translation required to re-center it // Therefore, [Tr] = [M_inv][Rnew_inv][Rold][M] } 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); + 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); + remapElement(selected, changes, extrat) if (angle) { if (tlist.numberOfItems) { - tlist.insertItemBefore(rnew, 0); + tlist.insertItemBefore(rnew, 0) } else { - tlist.appendItem(rnew); + tlist.appendItem(rnew) } } } @@ -790,10 +790,10 @@ export const recalculateDimensions = function (selected) { // if the transform list has been emptied, remove it if (tlist.numberOfItems === 0) { - selected.removeAttribute('transform'); + selected.removeAttribute('transform') } - batchCmd.addSubCommand(new ChangeElementCommand(selected, initial)); + batchCmd.addSubCommand(new ChangeElementCommand(selected, initial)) - return batchCmd; -}; + return batchCmd +} diff --git a/src/svgcanvas/sanitize.js b/src/svgcanvas/sanitize.js index 91990732..496f3a2e 100644 --- a/src/svgcanvas/sanitize.js +++ b/src/svgcanvas/sanitize.js @@ -6,10 +6,10 @@ * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller */ -import { getReverseNS, NS } from './namespaces.js'; -import { getHref, setHref, getUrlFromAttr } from './utilities.js'; +import { getReverseNS, NS } from './namespaces.js' +import { getHref, setHref, getUrlFromAttr } from './utilities.js' -const REVERSE_NS = getReverseNS(); +const REVERSE_NS = getReverseNS() // Todo: Split out into core attributes, presentation attributes, etc. so consistent /** @@ -18,102 +18,102 @@ const REVERSE_NS = getReverseNS(); * @type {PlainObject} */ /* eslint-disable max-len */ -const svgGenericWhiteList = [ 'class', 'id', 'display', 'transform', 'style' ]; +const svgGenericWhiteList = ['class', 'id', 'display', 'transform', 'style'] const svgWhiteList_ = { // SVG Elements - a: [ 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'xlink:href', 'xlink:title' ], - circle: [ 'clip-path', 'clip-rule', 'cx', 'cy', 'enable-background', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage' ], - clipPath: [ 'clipPathUnits' ], + a: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'xlink:href', 'xlink:title'], + circle: ['clip-path', 'clip-rule', 'cx', 'cy', 'enable-background', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage'], + clipPath: ['clipPathUnits'], defs: [], desc: [], - ellipse: [ 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage' ], - feBlend: [ 'in', 'in2' ], - feColorMatrix: [ 'in', 'type', 'value', 'result', 'values' ], - feComposite: [ 'in', 'operator', 'result', 'in2' ], - feFlood: [ 'flood-color', 'in', 'result', 'flood-opacity' ], - feGaussianBlur: [ 'color-interpolation-filters', 'in', 'requiredFeatures', 'stdDeviation', 'result' ], + ellipse: ['clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage'], + feBlend: ['in', 'in2'], + feColorMatrix: ['in', 'type', 'value', 'result', 'values'], + feComposite: ['in', 'operator', 'result', 'in2'], + feFlood: ['flood-color', 'in', 'result', 'flood-opacity'], + feGaussianBlur: ['color-interpolation-filters', 'in', 'requiredFeatures', 'stdDeviation', 'result'], feMerge: [], - feMergeNode: [ 'in' ], - feMorphology: [ 'in', 'operator', 'radius' ], - feOffset: [ 'dx', 'in', 'dy', 'result' ], - filter: [ 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y' ], - foreignObject: [ 'font-size', 'height', 'opacity', 'requiredFeatures', 'width', 'x', 'y' ], - g: [ 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor' ], - image: [ 'clip-path', 'clip-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'systemLanguage', 'width', 'x', 'xlink:href', 'xlink:title', 'y' ], - line: [ 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'x1', 'x2', 'y1', 'y2' ], - linearGradient: [ 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2' ], - marker: [ 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'se_type', 'systemLanguage', 'viewBox' ], - mask: [ 'height', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y' ], - metadata: [ ], - path: [ 'clip-path', 'clip-rule', 'd', 'enable-background', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage' ], - pattern: [ 'height', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y' ], - polygon: [ 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'sides', 'shape', 'edge', 'point', 'starRadiusMultiplier', 'r', 'radialshift' ], - polyline: [ 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'se:connector' ], - radialGradient: [ 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href' ], - rect: [ 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'width', 'x', 'y' ], - stop: [ 'offset', 'requiredFeatures', 'stop-opacity', 'systemLanguage', 'stop-color', 'gradientUnits', 'gradientTransform' ], - style: [ 'type' ], - svg: [ 'clip-path', 'clip-rule', 'enable-background', 'filter', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'systemLanguage', 'version', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'xmlns:oi', 'oi:animations', 'y', 'stroke-linejoin', 'fill-rule', 'aria-label', 'stroke-width', 'fill-rule', 'xml:space' ], - switch: [ 'requiredFeatures', 'systemLanguage' ], - symbol: [ 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'opacity', 'overflow', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'viewBox', 'width', 'height' ], - text: [ 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'text-anchor', 'x', 'xml:space', 'y' ], - textPath: [ 'method', 'requiredFeatures', 'spacing', 'startOffset', 'systemLanguage', 'xlink:href' ], + feMergeNode: ['in'], + feMorphology: ['in', 'operator', 'radius'], + feOffset: ['dx', 'in', 'dy', 'result'], + filter: ['color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y'], + foreignObject: ['font-size', 'height', 'opacity', 'requiredFeatures', 'width', 'x', 'y'], + g: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor'], + image: ['clip-path', 'clip-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'systemLanguage', 'width', 'x', 'xlink:href', 'xlink:title', 'y'], + line: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'x1', 'x2', 'y1', 'y2'], + linearGradient: ['gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2'], + marker: ['markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'se_type', 'systemLanguage', 'viewBox'], + mask: ['height', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y'], + metadata: [], + path: ['clip-path', 'clip-rule', 'd', 'enable-background', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage'], + pattern: ['height', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y'], + polygon: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'sides', 'shape', 'edge', 'point', 'starRadiusMultiplier', 'r', 'radialshift'], + polyline: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'se:connector'], + radialGradient: ['cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href'], + rect: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'width', 'x', 'y'], + stop: ['offset', 'requiredFeatures', 'stop-opacity', 'systemLanguage', 'stop-color', 'gradientUnits', 'gradientTransform'], + style: ['type'], + svg: ['clip-path', 'clip-rule', 'enable-background', 'filter', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'systemLanguage', 'version', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'xmlns:oi', 'oi:animations', 'y', 'stroke-linejoin', 'fill-rule', 'aria-label', 'stroke-width', 'fill-rule', 'xml:space'], + switch: ['requiredFeatures', 'systemLanguage'], + symbol: ['fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'opacity', 'overflow', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'viewBox', 'width', 'height'], + text: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'text-anchor', 'x', 'xml:space', 'y'], + textPath: ['method', 'requiredFeatures', 'spacing', 'startOffset', 'systemLanguage', 'xlink:href'], title: [], - tspan: [ 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'text-anchor', 'textLength', 'x', 'xml:space', 'y' ], - use: [ 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'width', 'x', 'xlink:href', 'y', 'overflow' ], + tspan: ['clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'text-anchor', 'textLength', 'x', 'xml:space', 'y'], + use: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'width', 'x', 'xlink:href', 'y', 'overflow'], // MathML Elements - annotation: [ 'encoding' ], - 'annotation-xml': [ 'encoding' ], - maction: [ 'actiontype', 'other', 'selection' ], - math: [ 'xmlns' ], - menclose: [ 'notation' ], + annotation: ['encoding'], + 'annotation-xml': ['encoding'], + maction: ['actiontype', 'other', 'selection'], + math: ['xmlns'], + menclose: ['notation'], merror: [], - mfrac: [ 'linethickness' ], - mi: [ 'mathvariant' ], + mfrac: ['linethickness'], + mi: ['mathvariant'], mmultiscripts: [], mn: [], - mo: [ 'fence', 'lspace', 'maxsize', 'minsize', 'rspace', 'stretchy' ], + mo: ['fence', 'lspace', 'maxsize', 'minsize', 'rspace', 'stretchy'], mover: [], - mpadded: [ 'lspace', 'width', 'height', 'depth', 'voffset' ], + mpadded: ['lspace', 'width', 'height', 'depth', 'voffset'], mphantom: [], mprescripts: [], mroot: [], - mrow: [ 'xlink:href', 'xlink:type', 'xmlns:xlink' ], - mspace: [ 'depth', 'height', 'width' ], + mrow: ['xlink:href', 'xlink:type', 'xmlns:xlink'], + mspace: ['depth', 'height', 'width'], msqrt: [], - mstyle: [ 'displaystyle', 'mathbackground', 'mathcolor', 'mathvariant', 'scriptlevel' ], + mstyle: ['displaystyle', 'mathbackground', 'mathcolor', 'mathvariant', 'scriptlevel'], msub: [], msubsup: [], msup: [], - mtable: [ 'align', 'columnalign', 'columnlines', 'columnspacing', 'displaystyle', 'equalcolumns', 'equalrows', 'frame', 'rowalign', 'rowlines', 'rowspacing', 'width' ], - mtd: [ 'columnalign', 'columnspan', 'rowalign', 'rowspan' ], + mtable: ['align', 'columnalign', 'columnlines', 'columnspacing', 'displaystyle', 'equalcolumns', 'equalrows', 'frame', 'rowalign', 'rowlines', 'rowspacing', 'width'], + mtd: ['columnalign', 'columnspan', 'rowalign', 'rowspan'], mtext: [], - mtr: [ 'columnalign', 'rowalign' ], + mtr: ['columnalign', 'rowalign'], munder: [], munderover: [], none: [], semantics: [] -}; +} /* eslint-enable max-len */ // add generic attributes to all elements of the whitelist -Object.keys(svgWhiteList_).forEach((element) => svgWhiteList_[element] = [ ...svgWhiteList_[element], ...svgGenericWhiteList ]); +Object.keys(svgWhiteList_).forEach((element) => { svgWhiteList_[element] = [...svgWhiteList_[element], ...svgGenericWhiteList] }) // Produce a Namespace-aware version of svgWhitelist -const svgWhiteListNS_ = {}; -Object.entries(svgWhiteList_).forEach(([ elt, atts ]) => { - const attNS = {}; - Object.entries(atts).forEach(function ([ _i, att ]) { +const svgWhiteListNS_ = {} +Object.entries(svgWhiteList_).forEach(([elt, atts]) => { + const attNS = {} + Object.entries(atts).forEach(function ([_i, att]) { if (att.includes(':')) { - const v = att.split(':'); - attNS[v[1]] = NS[(v[0]).toUpperCase()]; + const v = att.split(':') + attNS[v[1]] = NS[(v[0]).toUpperCase()] } else { - attNS[att] = att === 'xmlns' ? NS.XMLNS : null; + attNS[att] = att === 'xmlns' ? NS.XMLNS : null } - }); - svgWhiteListNS_[elt] = attNS; -}); + }) + svgWhiteListNS_[elt] = attNS +}) /** * Sanitizes the input node and its children. @@ -126,127 +126,127 @@ export const sanitizeSvg = function (node) { // Cleanup text nodes if (node.nodeType === 3) { // 3 === TEXT_NODE // Trim whitespace - node.nodeValue = node.nodeValue.trim(); + node.nodeValue = node.nodeValue.trim() // Remove if empty if (!node.nodeValue.length) { - node.remove(); + node.remove() } } // We only care about element nodes. // Automatically return for all non-element nodes, such as comments, etc. if (node.nodeType !== 1) { // 1 == ELEMENT_NODE - return; + return } - const doc = node.ownerDocument; - const parent = node.parentNode; + 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; + return } - const allowedAttrs = svgWhiteList_[node.nodeName]; - const allowedAttrsNS = svgWhiteListNS_[node.nodeName]; + const allowedAttrs = svgWhiteList_[node.nodeName] + const allowedAttrsNS = svgWhiteListNS_[node.nodeName] // if this element is supported, sanitize it if (typeof allowedAttrs !== 'undefined') { - const seAttrs = []; - let i = node.attributes.length; + const seAttrs = [] + let i = node.attributes.length while (i--) { // if the attribute is not in our whitelist, then remove it - const attr = node.attributes.item(i); - const attrName = attr.nodeName; - const attrLocalName = attr.localName; - const attrNsURI = attr.namespaceURI; + 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 ( attrNsURI !== allowedAttrsNS[attrLocalName] && attrNsURI !== NS.XMLNS - && !(attrNsURI === NS.XMLNS && REVERSE_NS[attr.value]) ) { + if (attrNsURI !== allowedAttrsNS[attrLocalName] && attrNsURI !== NS.XMLNS && + !(attrNsURI === NS.XMLNS && REVERSE_NS[attr.value])) { // Bypassing the whitelist to allow se: and oi: prefixes // We can add specific namepaces on demand for now. // Is there a more appropriate way to do this? - if (attrName.startsWith('se:') || attrName.startsWith('oi:')|| attrName.startsWith('data-')) { + if (attrName.startsWith('se:') || attrName.startsWith('oi:') || attrName.startsWith('data-')) { // We should bypass the namespace aswell - const seAttrNS = (attrName.startsWith('se:')) ? NS.SE : ((attrName.startsWith('oi:')) ? NS.OI : null); - seAttrs.push([ attrName, attr.value, seAttrNS ]); + const seAttrNS = (attrName.startsWith('se:')) ? NS.SE : ((attrName.startsWith('oi:')) ? NS.OI : null) + seAttrs.push([attrName, attr.value, seAttrNS]) } else { - console.warn(`sanitizeSvg: attribute ${attrName} in element ${node.nodeName} not in whitelist is removed`); - node.removeAttributeNS(attrNsURI, attrLocalName); + console.warn(`sanitizeSvg: attribute ${attrName} in element ${node.nodeName} not in whitelist is removed`) + node.removeAttributeNS(attrNsURI, attrLocalName) } } // For the style attribute, rewrite it in terms of XML presentational attributes if (attrName === 'style') { - const props = attr.value.split(';'); - let p = props.length; + const props = attr.value.split(';') + let p = props.length while (p--) { - const [ name, val ] = props[p].split(':'); - const styleAttrName = (name || '').trim(); - const styleAttrVal = (val || '').trim(); + 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); + node.setAttribute(styleAttrName, styleAttrVal) } } - node.removeAttribute('style'); + node.removeAttribute('style') } } - Object.values(seAttrs).forEach(([ att, val, ns ]) => { - node.setAttributeNS(ns, att, val); - }); + Object.values(seAttrs).forEach(([att, val, ns]) => { + node.setAttributeNS(ns, att, val) + }) // for some elements that have a xlink:href, ensure the URI refers to a local element // (but not for links) - const href = getHref(node); + const href = getHref(node) if (href && - [ 'filter', 'linearGradient', 'pattern', - 'radialGradient', 'textPath', 'use' ].includes(node.nodeName) && href[0] !== '#') { + ['filter', 'linearGradient', 'pattern', + 'radialGradient', 'textPath', 'use'].includes(node.nodeName) && href[0] !== '#') { // remove the attribute (but keep the element) - setHref(node, ''); - console.warn(`sanitizeSvg: attribute href in element ${node.nodeName} pointing to a non-local reference (${href}) is removed`); - node.removeAttributeNS(NS.XLINK, 'href'); + setHref(node, '') + console.warn(`sanitizeSvg: attribute href in element ${node.nodeName} pointing to a non-local reference (${href}) is removed`) + node.removeAttributeNS(NS.XLINK, 'href') } // Safari crashes on a without a xlink:href, so we just remove the node here if (node.nodeName === 'use' && !getHref(node)) { - console.warn(`sanitizeSvg: element ${node.nodeName} without a xlink:href is removed`); - node.remove(); - return; + console.warn(`sanitizeSvg: element ${node.nodeName} without a xlink:href is removed`) + node.remove() + return } // if the element has attributes pointing to a non-local reference, // need to remove the attribute - Object.values([ 'clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke' ], function (attr) { - let val = node.getAttribute(attr); + Object.values(['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke'], function (attr) { + let val = node.getAttribute(attr) if (val) { - val = getUrlFromAttr(val); + val = getUrlFromAttr(val) // simply check for first character being a '#' if (val && val[0] !== '#') { - node.setAttribute(attr, ''); - console.warn(`sanitizeSvg: attribute ${attr} in element ${node.nodeName} pointing to a non-local reference (${val}) is removed`); - node.removeAttribute(attr); + node.setAttribute(attr, '') + console.warn(`sanitizeSvg: attribute ${attr} in element ${node.nodeName} pointing to a non-local reference (${val}) is removed`) + node.removeAttribute(attr) } } - }); + }) // recurse to children - i = node.childNodes.length; - while (i--) { sanitizeSvg(node.childNodes.item(i)); } + i = node.childNodes.length + while (i--) { sanitizeSvg(node.childNodes.item(i)) } // else (element not supported), remove it } 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 - console.warn(`sanitizeSvg: element ${node.nodeName} not supported is removed`); - const children = []; + console.warn(`sanitizeSvg: element ${node.nodeName} not supported is removed`) + const children = [] while (node.hasChildNodes()) { - children.push(parent.insertBefore(node.firstChild, node)); + children.push(parent.insertBefore(node.firstChild, node)) } // remove this node from the document altogether - node.remove(); + node.remove() // call sanitizeSvg on each of those children - let i = children.length; - while (i--) { sanitizeSvg(children[i]); } + let i = children.length + while (i--) { sanitizeSvg(children[i]) } } -}; +} diff --git a/src/svgcanvas/select.js b/src/svgcanvas/select.js index c2b9b1a5..abfa0fb4 100644 --- a/src/svgcanvas/select.js +++ b/src/svgcanvas/select.js @@ -6,13 +6,13 @@ * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller */ -import { isTouch, isWebkit } from '../common/browser.js'; // , isOpera -import { getRotationAngle, getBBox, getStrokedBBox, isNullish } from './utilities.js'; -import { transformListToTransform, transformBox, transformPoint } from './math.js'; +import { isTouch, isWebkit } from '../common/browser.js' // , isOpera +import { getRotationAngle, getBBox, getStrokedBBox, isNullish } from './utilities.js' +import { transformListToTransform, transformBox, transformPoint } from './math.js' -let svgCanvas; -let selectorManager_; // A Singleton -const gripRadius = isTouch() ? 10 : 4; +let svgCanvas +let selectorManager_ // A Singleton +const gripRadius = isTouch() ? 10 : 4 /** * Private class for DOM element selection boxes. @@ -23,21 +23,21 @@ export class 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). */ - constructor(id, elem, bbox) { + constructor (id, elem, bbox) { // this is the selector's unique number - this.id = id; + this.id = id // this holds a reference to the element for which this selector is being used - this.selectedElement = elem; + this.selectedElement = elem // this is a flag used internally to track whether the selector is being used or not - this.locked = true; + this.locked = true // this holds a reference to the element that holds all visual elements of the selector this.selectorGroup = svgCanvas.createSVGElement({ element: 'g', attr: { id: ('selectorGroup' + this.id) } - }); + }) // this holds a reference to the path rect this.selectorRect = svgCanvas.createSVGElement({ @@ -51,8 +51,8 @@ export class Selector { // need to specify this so that the rect is not selectable style: 'pointer-events:none' } - }); - this.selectorGroup.append(this.selectorRect); + }) + this.selectorGroup.append(this.selectorRect) // this holds a reference to the grip coordinates for this selector this.gripCoords = { @@ -64,9 +64,9 @@ export class Selector { s: null, sw: null, w: null - }; + } - this.reset(this.selectedElement, bbox); + this.reset(this.selectedElement, bbox) } /** @@ -75,11 +75,11 @@ export class Selector { * @param {module:utilities.BBoxObject} bbox - Optional bbox to use for reset (prevents duplicate getBBox call). * @returns {void} */ - 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') } /** @@ -87,14 +87,14 @@ export class 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; + 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)); + this.selectorGroup.append(selectorManager_.selectorGripsGroup) + Selector.updateGripCursors(getRotationAngle(elem)) } } @@ -103,132 +103,132 @@ export class Selector { * @param {module:utilities.BBoxObject} [bbox] - BBox to use for resize (prevents duplicate getBBox call). * @returns {void} */ - resize(bbox) { - const dataStorage = svgCanvas.getDataStorage(); - const selectedBox = this.selectorRect; - const mgr = selectorManager_; - const selectedGrips = mgr.selectorGrips; - const selected = this.selectedElement; - const zoom = svgCanvas.getZoom(); - let offset = 1 / zoom; - const sw = selected.getAttribute('stroke-width'); + resize (bbox) { + const dataStorage = svgCanvas.getDataStorage() + const selectedBox = this.selectorRect + const mgr = selectorManager_ + const selectedGrips = mgr.selectorGrips + const selected = this.selectedElement + const zoom = svgCanvas.getZoom() + let offset = 1 / zoom + const sw = selected.getAttribute('stroke-width') if (selected.getAttribute('stroke') !== 'none' && !isNaN(sw)) { - offset += (sw / 2); + offset += (sw / 2) } - const { tagName } = selected; + const { tagName } = selected if (tagName === 'text') { - offset += 2 / zoom; + offset += 2 / zoom } // loop and transform our bounding box until we reach our first rotation - const tlist = selected.transform.baseVal; - const m = transformListToTransform(tlist).matrix; + const tlist = selected.transform.baseVal + 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 *= zoom; - m.f *= zoom; + m.e *= zoom + m.f *= zoom if (!bbox) { - bbox = getBBox(selected); + 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' && !dataStorage.has(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 ]); + const strokedBbox = getStrokedBBox([selected.childNodes]) if (strokedBbox) { - bbox = strokedBbox; + bbox = strokedBbox } } // apply the transforms - const l = bbox.x; const t = bbox.y; const w = bbox.width; const h = bbox.height; + const l = bbox.x; const t = bbox.y; const w = bbox.width; const 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 // * - offset *= zoom; + offset *= zoom - const nbox = transformBox(l * zoom, t * zoom, w * zoom, h * zoom, m); - const { aabox } = nbox; - let nbax = aabox.x - offset; - let nbay = aabox.y - offset; - let nbaw = aabox.width + (offset * 2); - let nbah = aabox.height + (offset * 2); + const nbox = transformBox(l * zoom, t * zoom, w * zoom, h * zoom, m) + const { aabox } = nbox + let nbax = aabox.x - offset + let nbay = aabox.y - offset + let nbaw = aabox.width + (offset * 2) + let nbah = aabox.height + (offset * 2) // now if the shape is rotated, un-rotate it - const cx = nbax + nbaw / 2; - const cy = nbay + nbah / 2; + const cx = nbax + nbaw / 2 + const cy = nbay + nbah / 2 - const angle = getRotationAngle(selected); + const angle = getRotationAngle(selected) if (angle) { - const rot = svgCanvas.getSvgRoot().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); + const rot = svgCanvas.getSvgRoot().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 - const { tl } = nbox; - let minx = tl.x; - let miny = tl.y; - let maxx = tl.x; - let maxy = tl.y; + const { tl } = nbox + let minx = tl.x + let miny = tl.y + let maxx = tl.x + let maxy = tl.y - const { min, max } = Math; + 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; + minx = min(minx, min(nbox.tr.x, min(nbox.bl.x, nbox.br.x))) - offset + miny = min(miny, min(nbox.tr.y, min(nbox.bl.y, nbox.br.y))) - offset + maxx = max(maxx, max(nbox.tr.x, max(nbox.bl.x, nbox.br.x))) + offset + maxy = max(maxy, max(nbox.tr.y, max(nbox.bl.y, nbox.br.y))) + offset - nbax = minx; - nbay = miny; - nbaw = (maxx - minx); - nbah = (maxy - miny); + nbax = minx + nbay = miny + nbaw = (maxx - minx) + nbah = (maxy - miny) } const dstr = 'M' + nbax + ',' + nbay + ' L' + (nbax + nbaw) + ',' + nbay + ' ' + (nbax + nbaw) + ',' + (nbay + nbah) + - ' ' + nbax + ',' + (nbay + nbah) + 'z'; + ' ' + nbax + ',' + (nbay + nbah) + 'z' - const xform = angle ? 'rotate(' + [ angle, cx, cy ].join(',') + ')' : ''; + const xform = angle ? 'rotate(' + [angle, cx, cy].join(',') + ')' : '' // 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 ] - }; - selectedBox.setAttribute('d', dstr); - this.selectorGroup.setAttribute('transform', xform); - Object.entries(this.gripCoords).forEach(([ dir, coords ]) => { - selectedGrips[dir].setAttribute('cx', coords[0]); - selectedGrips[dir].setAttribute('cy', coords[1]); - }); + 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] + } + selectedBox.setAttribute('d', dstr) + this.selectorGroup.setAttribute('transform', xform) + 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.rotateGripConnector.setAttribute('x1', nbax + (nbaw) / 2) + mgr.rotateGripConnector.setAttribute('y1', nbay) + mgr.rotateGripConnector.setAttribute('x2', nbax + (nbaw) / 2) + mgr.rotateGripConnector.setAttribute('y2', nbay - (gripRadius * 5)) - mgr.rotateGrip.setAttribute('cx', nbax + (nbaw) / 2); - mgr.rotateGrip.setAttribute('cy', nbay - (gripRadius * 5)); + mgr.rotateGrip.setAttribute('cx', nbax + (nbaw) / 2) + mgr.rotateGrip.setAttribute('cy', nbay - (gripRadius * 5)) // } } @@ -238,17 +238,17 @@ export class Selector { * @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; } + 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--; + dirArr.push(dirArr.shift()) + steps-- } Object.values(selectorManager_.selectorGrips).forEach((gripElement, i) => { - gripElement.setAttribute('style', ('cursor:' + dirArr[i] + '-resize')); - }); + gripElement.setAttribute('style', ('cursor:' + dirArr[i] + '-resize')) + }) } } @@ -259,18 +259,18 @@ export class SelectorManager { /** * Sets up properties and calls `initGroup`. */ - constructor() { + constructor () { // this will hold the element that contains all selector rects/grips - this.selectorParentGroup = null; + this.selectorParentGroup = null // this is a special rect that is used for multi-select - this.rubberBandBox = null; + this.rubberBandBox = null // this will hold objects of type Selector (see above) - this.selectors = []; + this.selectors = [] // this holds a map of SVG elements to their Selector object - this.selectorMap = {}; + this.selectorMap = {} // this holds a reference to the grip elements this.selectorGrips = { @@ -282,41 +282,41 @@ export class SelectorManager { s: null, sw: null, w: null - }; + } - this.selectorGripsGroup = null; - this.rotateGripConnector = null; - this.rotateGrip = null; + this.selectorGripsGroup = null + this.rotateGripConnector = null + this.rotateGrip = null - this.initGroup(); + this.initGroup() } /** * Resets the parent selector group element. * @returns {void} */ - initGroup() { - const dataStorage = svgCanvas.getDataStorage(); + initGroup () { + const dataStorage = svgCanvas.getDataStorage() // remove old selector parent group if it existed if (this.selectorParentGroup && this.selectorParentGroup.parentNode) { - this.selectorParentGroup.remove(); + this.selectorParentGroup.remove() } // create parent selector group and add it to svgroot this.selectorParentGroup = svgCanvas.createSVGElement({ element: 'g', attr: { id: 'selectorParentGroup' } - }); + }) this.selectorGripsGroup = svgCanvas.createSVGElement({ element: 'g', attr: { display: 'none' } - }); - this.selectorParentGroup.append(this.selectorGripsGroup); - svgCanvas.getSvgRoot().append(this.selectorParentGroup); + }) + this.selectorParentGroup.append(this.selectorGripsGroup) + svgCanvas.getSvgRoot().append(this.selectorParentGroup) - this.selectorMap = {}; - this.selectors = []; - this.rubberBandBox = null; + this.selectorMap = {} + this.selectors = [] + this.rubberBandBox = null // add the corner grips Object.keys(this.selectorGrips).forEach((dir) => { @@ -334,13 +334,13 @@ export class SelectorManager { 'stroke-width': 2, 'pointer-events': 'all' } - }); + }) - dataStorage.put(grip, 'dir', dir); - dataStorage.put(grip, 'type', 'resize'); - this.selectorGrips[dir] = grip; - this.selectorGripsGroup.append(grip); - }); + dataStorage.put(grip, 'dir', dir) + dataStorage.put(grip, 'type', 'resize') + this.selectorGrips[dir] = grip + this.selectorGripsGroup.append(grip) + }) // add rotator elems this.rotateGripConnector = @@ -351,8 +351,8 @@ export class SelectorManager { stroke: '#22C', 'stroke-width': '1' } - }); - this.selectorGripsGroup.append(this.rotateGripConnector); + }) + this.selectorGripsGroup.append(this.rotateGripConnector) this.rotateGrip = svgCanvas.createSVGElement({ @@ -365,13 +365,13 @@ export class SelectorManager { 'stroke-width': 2, style: `cursor:url(${svgCanvas.curConfig.imgPath}/rotate.svg) 12 12, auto;` } - }); - this.selectorGripsGroup.append(this.rotateGrip); - dataStorage.put(this.rotateGrip, 'type', 'rotate'); + }) + this.selectorGripsGroup.append(this.rotateGrip) + dataStorage.put(this.rotateGrip, 'type', 'rotate') - if (document.getElementById('canvasBackground')) { return; } + if (document.getElementById('canvasBackground')) { return } - const [ width, height ] = svgCanvas.curConfig.dimensions; + const [width, height] = svgCanvas.curConfig.dimensions const canvasbg = svgCanvas.createSVGElement({ element: 'svg', attr: { @@ -383,7 +383,7 @@ export class SelectorManager { overflow: (isWebkit() ? 'none' : 'visible'), // Chrome 7 has a problem with this when zooming out style: 'pointer-events:none' } - }); + }) const rect = svgCanvas.createSVGElement({ element: 'rect', @@ -397,9 +397,9 @@ export class SelectorManager { fill: '#FFF', style: 'pointer-events:none' } - }); - canvasbg.append(rect); - svgCanvas.getSvgRoot().insertBefore(canvasbg, svgCanvas.getSvgContent()); + }) + canvasbg.append(rect) + svgCanvas.getSvgRoot().insertBefore(canvasbg, svgCanvas.getSvgContent()) } /** @@ -408,28 +408,28 @@ export class SelectorManager { * @param {module:utilities.BBoxObject} [bbox] - Optional bbox to use for reset (prevents duplicate getBBox call). * @returns {Selector} The selector based on the given element */ - requestSelector(elem, bbox) { - if (!elem) { return null; } + requestSelector (elem, bbox) { + if (!elem) { return null } - const N = this.selectors.length; + 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]; + 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]; + this.selectors[i].locked = true + this.selectors[i].reset(elem, bbox) + this.selectorMap[elem.id] = this.selectors[i] + return this.selectors[i] } } // if we reached here, no available selectors were found, we create one - this.selectors[N] = new Selector(N, elem, bbox); - this.selectorParentGroup.append(this.selectors[N].selectorGroup); - this.selectorMap[elem.id] = this.selectors[N]; - return this.selectors[N]; + 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] } /** @@ -438,27 +438,27 @@ export class SelectorManager { * @param {Element} elem - DOM element to remove the selector for * @returns {void} */ - releaseSelector(elem) { - if (isNullish(elem)) { return; } - const N = this.selectors.length; - const sel = this.selectorMap[elem.id]; + releaseSelector (elem) { + if (isNullish(elem)) { return } + const N = this.selectors.length + const sel = this.selectorMap[elem.id] if (sel && !sel.locked) { // TODO(codedread): Ensure this exists in this module. - console.warn('WARNING! selector was released but was already unlocked'); + console.warn('WARNING! selector was released but was already unlocked') } 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); + 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) {/* empty fn */ } + sel.selectorGroup.setAttribute('display', 'none') + } catch (e) { /* empty fn */ } - break; + break } } } @@ -467,7 +467,7 @@ export class SelectorManager { * @returns {SVGRectElement} The rubberBandBox DOM element. This is the rectangle drawn by * the user for selecting/zooming */ - getRubberBandBox() { + getRubberBandBox () { if (!this.rubberBandBox) { this.rubberBandBox = svgCanvas.createSVGElement({ @@ -481,10 +481,10 @@ export class SelectorManager { display: 'none', style: 'pointer-events:none' } - }); - this.selectorParentGroup.append(this.rubberBandBox); + }) + this.selectorParentGroup.append(this.rubberBandBox) } - return this.rubberBandBox; + return this.rubberBandBox } } @@ -531,12 +531,12 @@ export class SelectorManager { * @returns {void} */ export const init = (canvas) => { - svgCanvas = canvas; - selectorManager_ = new SelectorManager(); -}; + svgCanvas = canvas + selectorManager_ = new SelectorManager() +} /** * @function module:select.getSelectorManager * @returns {module:select.SelectorManager} The SelectorManager instance. */ -export const getSelectorManager = () => selectorManager_; +export const getSelectorManager = () => selectorManager_ diff --git a/src/svgcanvas/selected-elem.js b/src/svgcanvas/selected-elem.js index 5a70c4d4..7854ecc8 100644 --- a/src/svgcanvas/selected-elem.js +++ b/src/svgcanvas/selected-elem.js @@ -6,29 +6,29 @@ * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller */ -import { NS } from './namespaces.js'; -import * as hstry from './history.js'; -import * as pathModule from './path.js'; +import { NS } from './namespaces.js' +import * as hstry from './history.js' +import * as pathModule from './path.js' import { isNullish, getStrokedBBoxDefaultVisible, setHref, getElem, getHref, getVisibleElements, findDefs, getRotationAngle, getRefElem, getBBox as utilsGetBBox, walkTreePost, assignAttributes, getFeGaussianBlur -} from './utilities.js'; +} from './utilities.js' import { transformPoint, matrixMultiply, transformListToTransform -} from './math.js'; +} from './math.js' import { recalculateDimensions -} from './recalculate.js'; +} from './recalculate.js' import { isGecko -} from '../common/browser.js'; // , supportsEditableText -import { getParents } from '../editor/components/jgraduate/Util.js'; +} from '../common/browser.js' // , supportsEditableText +import { getParents } from '../editor/components/jgraduate/Util.js' const { MoveElementCommand, BatchCommand, InsertElementCommand, RemoveElementCommand, ChangeElementCommand -} = hstry; +} = hstry -let svgCanvas = null; +let svgCanvas = null /** * @function module:selected-elem.init @@ -36,8 +36,8 @@ let svgCanvas = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; -}; + svgCanvas = canvas +} /** * Repositions the selected element to the bottom in the DOM to appear on top of @@ -47,20 +47,20 @@ export const init = function (canvas) { * @returns {void} */ export const moveToTopSelectedElem = function () { - const [ selected ] = svgCanvas.getSelectedElements(); + const [selected] = svgCanvas.getSelectedElements() if (!isNullish(selected)) { - const t = selected; - const oldParent = t.parentNode; - const oldNextSibling = t.nextSibling; - t.parentNode.append(t); + const t = selected + const oldParent = t.parentNode + const oldNextSibling = t.nextSibling + t.parentNode.append(t) // If the element actually moved position, add the command and fire the changed // event handler. if (oldNextSibling !== t.nextSibling) { - svgCanvas.addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, 'top')); - svgCanvas.call('changed', [ t ]); + svgCanvas.addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, 'top')) + svgCanvas.call('changed', [t]) } } -}; +} /** * Repositions the selected element to the top in the DOM to appear under @@ -70,29 +70,29 @@ export const moveToTopSelectedElem = function () { * @returns {void} */ export const moveToBottomSelectedElem = function () { - const [ selected ] = svgCanvas.getSelectedElements(); + const [selected] = svgCanvas.getSelectedElements() if (!isNullish(selected)) { - let t = selected; - const oldParent = t.parentNode; - const oldNextSibling = t.nextSibling; - let { firstChild } = t.parentNode; + let t = selected + const oldParent = t.parentNode + const oldNextSibling = t.nextSibling + let { firstChild } = t.parentNode if (firstChild.tagName === 'title') { - firstChild = firstChild.nextSibling; + 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; + firstChild = firstChild.nextSibling } - t = t.parentNode.insertBefore(t, firstChild); + 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) { - svgCanvas.addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, 'bottom')); - svgCanvas.call('changed', [ t ]); + svgCanvas.addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, 'bottom')) + svgCanvas.call('changed', [t]) } } -}; +} /** * Moves the select element up or down the stack, based on the visibly @@ -103,43 +103,43 @@ export const moveToBottomSelectedElem = function () { * @returns {void} */ export const moveUpDownSelected = function (dir) { - const selectedElements = svgCanvas.getSelectedElements(); - const selected = selectedElements[0]; - if (!selected) { return; } + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] + if (!selected) { return } - svgCanvas.setCurBBoxes([]); - let closest; let foundCur; + svgCanvas.setCurBBoxes([]) + let closest; let foundCur // jQuery sorts this list - const list = svgCanvas.getIntersectionList(getStrokedBBoxDefaultVisible([ selected ])); - if (dir === 'Down') { list.reverse(); } + const list = svgCanvas.getIntersectionList(getStrokedBBoxDefaultVisible([selected])) + if (dir === 'Down') { list.reverse() } Array.prototype.forEach.call(list, function (el) { if (!foundCur) { if (el === selected) { - foundCur = true; + foundCur = true } - return true; + return true } - closest = el; - return false; - }); - if (!closest) { return; } + closest = el + return false + }) + if (!closest) { return } - const t = selected; - const oldParent = t.parentNode; - const oldNextSibling = t.nextSibling; + const t = selected + const oldParent = t.parentNode + const oldNextSibling = t.nextSibling if (dir === 'Down') { - closest.insertAdjacentElement('beforebegin', t); + closest.insertAdjacentElement('beforebegin', t) } else { - closest.insertAdjacentElement('afterend', t); + closest.insertAdjacentElement('afterend', t) } // If the element actually moved position, add the command and fire the changed // event handler. if (oldNextSibling !== t.nextSibling) { - svgCanvas.addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, 'Move ' + dir)); - svgCanvas.call('changed', [ t ]); + svgCanvas.addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, 'Move ' + dir)) + svgCanvas.call('changed', [t]) } -}; +} /** * Moves selected elements on the X/Y axis. @@ -152,51 +152,51 @@ export const moveUpDownSelected = function (dir) { */ export const moveSelectedElements = function (dx, dy, undoable = true) { - const selectedElements = svgCanvas.getSelectedElements(); - const zoom = svgCanvas.getZoom(); + const selectedElements = svgCanvas.getSelectedElements() + const zoom = svgCanvas.getZoom() // if undoable is not sent, default to true // if single values, scale them to the zoom if (!Array.isArray(dx)) { - dx /= zoom; - dy /= zoom; + dx /= zoom + dy /= zoom } - const batchCmd = new BatchCommand('position'); + const batchCmd = new BatchCommand('position') selectedElements.forEach((selected, i) => { if (selected) { - const xform = svgCanvas.getSvgRoot().createSVGTransform(); - const tlist = selected.transform?.baseVal; + const xform = svgCanvas.getSvgRoot().createSVGTransform() + const tlist = selected.transform?.baseVal // dx and dy could be arrays if (Array.isArray(dx)) { - xform.setTranslate(dx[i], dy[i]); + xform.setTranslate(dx[i], dy[i]) } else { - xform.setTranslate(dx, dy); + xform.setTranslate(dx, dy) } if (tlist.numberOfItems) { - tlist.insertItemBefore(xform, 0); + tlist.insertItemBefore(xform, 0) } else { - tlist.appendItem(xform); + tlist.appendItem(xform) } - const cmd = recalculateDimensions(selected); + const cmd = recalculateDimensions(selected) if (cmd) { - batchCmd.addSubCommand(cmd); + batchCmd.addSubCommand(cmd) } - svgCanvas.gettingSelectorManager().requestSelector(selected).resize(); + svgCanvas.gettingSelectorManager().requestSelector(selected).resize() } - }); + }) if (!batchCmd.isEmpty()) { if (undoable) { - svgCanvas.addCommandToHistory(batchCmd); + svgCanvas.addCommandToHistory(batchCmd) } - svgCanvas.call('changed', selectedElements); - return batchCmd; + svgCanvas.call('changed', selectedElements) + return batchCmd } - return undefined; -}; + return undefined +} /** * Create deep DOM copies (clones) of all selected elements and move them slightly @@ -207,20 +207,20 @@ export const moveSelectedElements = function (dx, dy, undoable = true) { * @returns {void} */ export const cloneSelectedElements = function (x, y) { - const selectedElements = svgCanvas.getSelectedElements(); - const currentGroup = svgCanvas.getCurrentGroup(); - let i; let elem; - const batchCmd = new BatchCommand('Clone Elements'); + const selectedElements = svgCanvas.getSelectedElements() + const currentGroup = svgCanvas.getCurrentGroup() + let i; let elem + const batchCmd = new BatchCommand('Clone Elements') // find all the elements selected (stop at first null) - const len = selectedElements.length; + const len = selectedElements.length - function index(el) { - if (!el) return -1; - let i = 0; + function index (el) { + if (!el) return -1 + let i = 0 do { - i++; - } while (el == el.previousElementSibling); - return i; + i++ + } while (el === el.previousElementSibling) + return i } /** @@ -229,34 +229,34 @@ export const cloneSelectedElements = function (x, y) { * @param {Element} b * @returns {Integer} */ - function sortfunction(a, b) { - return (index(b) - index(a)); + function sortfunction (a, b) { + return (index(b) - index(a)) } - selectedElements.sort(sortfunction); + selectedElements.sort(sortfunction) for (i = 0; i < len; ++i) { - elem = selectedElements[i]; - if (isNullish(elem)) { break; } + elem = selectedElements[i] + if (isNullish(elem)) { break } } // use slice to quickly get the subset of elements we need - const copiedElements = selectedElements.slice(0, i); - svgCanvas.clearSelection(true); + const copiedElements = selectedElements.slice(0, i) + svgCanvas.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 = svgCanvas.getDrawing(); - i = copiedElements.length; + const drawing = svgCanvas.getDrawing() + 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(elem)); + (currentGroup || drawing.getCurrentLayer()).append(elem) + batchCmd.addSubCommand(new InsertElementCommand(elem)) } if (!batchCmd.isEmpty()) { - svgCanvas.addToSelection(copiedElements.reverse()); // Need to reverse for correct selection-adding - moveSelectedElements(x, y, false); - svgCanvas.addCommandToHistory(batchCmd); + svgCanvas.addToSelection(copiedElements.reverse()) // Need to reverse for correct selection-adding + moveSelectedElements(x, y, false) + svgCanvas.addCommandToHistory(batchCmd) } -}; +} /** * Aligns selected elements. * @function module:selected-elem.SvgCanvas#alignSelectedElements @@ -265,101 +265,101 @@ export const cloneSelectedElements = function (x, y) { * @returns {void} */ export const alignSelectedElements = function (type, relativeTo) { - const selectedElements = svgCanvas.getSelectedElements(); - const bboxes = []; // angles = []; - const len = selectedElements.length; - if (!len) { return; } - let minx = Number.MAX_VALUE; let maxx = Number.MIN_VALUE; - let miny = Number.MAX_VALUE; let maxy = Number.MIN_VALUE; - let curwidth = Number.MIN_VALUE; let curheight = Number.MIN_VALUE; + const selectedElements = svgCanvas.getSelectedElements() + const bboxes = [] // angles = []; + const len = selectedElements.length + if (!len) { return } + let minx = Number.MAX_VALUE; let maxx = Number.MIN_VALUE + let miny = Number.MAX_VALUE; let maxy = Number.MIN_VALUE + let curwidth = Number.MIN_VALUE; let curheight = Number.MIN_VALUE for (let i = 0; i < len; ++i) { - if (isNullish(selectedElements[i])) { break; } - const elem = selectedElements[i]; - bboxes[i] = getStrokedBBoxDefaultVisible([ elem ]); + 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' || type === 'left' || type === 'center' || type === 'right') && + case 'smallest': + if (((type === 'l' || type === 'c' || type === 'r' || type === 'left' || type === 'center' || type === 'right') && (curwidth === Number.MIN_VALUE || curwidth > bboxes[i].width)) || ((type === 't' || type === 'm' || type === 'b' || type === 'top' || type === 'middle' || type === 'bottom') && (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' || type === 'left' || type === 'center' || type === 'right') && + ) { + 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' || type === 'left' || type === 'center' || type === 'right') && (curwidth === Number.MIN_VALUE || curwidth < bboxes[i].width)) || ((type === 't' || type === 'm' || type === 'b' || type === 'top' || type === 'middle' || type === 'bottom') && (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; + ) { + 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 = svgCanvas.getContentW(); - maxy = svgCanvas.getContentH(); + minx = 0 + miny = 0 + maxx = svgCanvas.getContentW() + maxy = svgCanvas.getContentH() } - const dx = new Array(len); - const dy = new Array(len); + const dx = new Array(len) + const dy = new Array(len) for (let i = 0; i < len; ++i) { - if (isNullish(selectedElements[i])) { break; } + if (isNullish(selectedElements[i])) { break } // const elem = selectedElements[i]; - const bbox = bboxes[i]; - dx[i] = 0; - dy[i] = 0; + const bbox = bboxes[i] + dx[i] = 0 + dy[i] = 0 switch (type) { - case 'l': // left (horizontal) - case 'left': // left (horizontal) - dx[i] = minx - bbox.x; - break; - case 'c': // center (horizontal) - case 'center': // center (horizontal) - dx[i] = (minx + maxx) / 2 - (bbox.x + bbox.width / 2); - break; - case 'r': // right (horizontal) - case 'right': // right (horizontal) - dx[i] = maxx - (bbox.x + bbox.width); - break; - case 't': // top (vertical) - case 'top': // top (vertical) - dy[i] = miny - bbox.y; - break; - case 'm': // middle (vertical) - case 'middle': // middle (vertical) - dy[i] = (miny + maxy) / 2 - (bbox.y + bbox.height / 2); - break; - case 'b': // bottom (vertical) - case 'bottom': // bottom (vertical) - dy[i] = maxy - (bbox.y + bbox.height); - break; + case 'l': // left (horizontal) + case 'left': // left (horizontal) + dx[i] = minx - bbox.x + break + case 'c': // center (horizontal) + case 'center': // center (horizontal) + dx[i] = (minx + maxx) / 2 - (bbox.x + bbox.width / 2) + break + case 'r': // right (horizontal) + case 'right': // right (horizontal) + dx[i] = maxx - (bbox.x + bbox.width) + break + case 't': // top (vertical) + case 'top': // top (vertical) + dy[i] = miny - bbox.y + break + case 'm': // middle (vertical) + case 'middle': // middle (vertical) + dy[i] = (miny + maxy) / 2 - (bbox.y + bbox.height / 2) + break + case 'b': // bottom (vertical) + case 'bottom': // bottom (vertical) + dy[i] = maxy - (bbox.y + bbox.height) + break } } - moveSelectedElements(dx, dy); -}; + moveSelectedElements(dx, dy) +} /** * Removes all selected elements from the DOM and adds the change to the @@ -369,42 +369,42 @@ export const alignSelectedElements = function (type, relativeTo) { * @returns {void} */ export const deleteSelectedElements = function () { - const selectedElements = svgCanvas.getSelectedElements(); - const batchCmd = new BatchCommand('Delete Elements'); - const len = selectedElements.length; - const selectedCopy = []; // selectedElements is being deleted + const selectedElements = svgCanvas.getSelectedElements() + const batchCmd = new BatchCommand('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; } + const selected = selectedElements[i] + if (isNullish(selected)) { break } - let parent = selected.parentNode; - let t = selected; + let parent = selected.parentNode + let t = selected // this will unselect the element and remove the selectedOutline - svgCanvas.gettingSelectorManager().releaseSelector(t); + svgCanvas.gettingSelectorManager().releaseSelector(t) // Remove the path if present. - pathModule.removePath_(t.id); + pathModule.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; + t = parent + parent = parent.parentNode } - const { nextSibling } = t; - t.remove(); - const elem = t; - selectedCopy.push(selected); // for the copy - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); + const { nextSibling } = t + t.remove() + const elem = t + selectedCopy.push(selected) // for the copy + batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)) } - svgCanvas.setEmptySelectedElements(); + svgCanvas.setEmptySelectedElements() - if (!batchCmd.isEmpty()) { svgCanvas.addCommandToHistory(batchCmd); } - svgCanvas.call('changed', selectedCopy); - svgCanvas.clearSelection(); -}; + if (!batchCmd.isEmpty()) { svgCanvas.addCommandToHistory(batchCmd) } + svgCanvas.call('changed', selectedCopy) + svgCanvas.clearSelection() +} /** * Remembers the current selected elements on the clipboard. @@ -412,17 +412,17 @@ export const deleteSelectedElements = function () { * @returns {void} */ export const copySelectedElements = function () { - const selectedElements = svgCanvas.getSelectedElements(); + const selectedElements = svgCanvas.getSelectedElements() const data = - JSON.stringify(selectedElements.map((x) => svgCanvas.getJsonFromSvgElements(x))); + JSON.stringify(selectedElements.map((x) => svgCanvas.getJsonFromSvgElements(x))) // Use sessionStorage for the clipboard data. - sessionStorage.setItem(svgCanvas.getClipboardID(), data); - svgCanvas.flashStorage(); + sessionStorage.setItem(svgCanvas.getClipboardID(), data) + svgCanvas.flashStorage() // Context menu might not exist (it is provided by editor.js). - const canvMenu = document.getElementById('se-cmenu_canvas'); - canvMenu.setAttribute('enablemenuitems', '#paste,#paste_in_place'); -}; + const canvMenu = document.getElementById('se-cmenu_canvas') + canvMenu.setAttribute('enablemenuitems', '#paste,#paste_in_place') +} /** * Wraps all the selected elements in a group (`g`) element. @@ -432,24 +432,24 @@ export const copySelectedElements = function () { * @returns {void} */ export const groupSelectedElements = function (type, urlArg) { - const selectedElements = svgCanvas.getSelectedElements(); - if (!type) { type = 'g'; } - let cmdStr = ''; - let url; + const selectedElements = svgCanvas.getSelectedElements() + 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; - } + case 'a': { + cmdStr = 'Make hyperlink' + url = urlArg || '' + break + } default: { + type = 'g' + cmdStr = 'Group Elements' + break + } } - const batchCmd = new BatchCommand(cmdStr); + const batchCmd = new BatchCommand(cmdStr) // create and insert the group element const g = svgCanvas.addSVGElemensFromJson({ @@ -457,32 +457,32 @@ export const groupSelectedElements = function (type, urlArg) { attr: { id: svgCanvas.getNextId() } - }); + }) if (type === 'a') { - setHref(g, url); + setHref(g, url) } - batchCmd.addSubCommand(new InsertElementCommand(g)); + batchCmd.addSubCommand(new InsertElementCommand(g)) // now move all children into the group - let i = selectedElements.length; + let i = selectedElements.length while (i--) { - let elem = selectedElements[i]; - if (isNullish(elem)) { continue; } + let elem = selectedElements[i] + if (isNullish(elem)) { continue } if (elem.parentNode.tagName === 'a' && elem.parentNode.childNodes.length === 1) { - elem = elem.parentNode; + elem = elem.parentNode } - const oldNextSibling = elem.nextSibling; - const oldParent = elem.parentNode; - g.append(elem); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)); + const oldNextSibling = elem.nextSibling + const oldParent = elem.parentNode + g.append(elem) + batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)) } - if (!batchCmd.isEmpty()) { svgCanvas.addCommandToHistory(batchCmd); } + if (!batchCmd.isEmpty()) { svgCanvas.addCommandToHistory(batchCmd) } // update selection - svgCanvas.selectOnly([ g ], true); -}; + svgCanvas.selectOnly([g], true) +} /** * Pushes all appropriate parent group properties down to its children, then @@ -493,14 +493,14 @@ export const groupSelectedElements = function (type, urlArg) { * @returns {BatchCommand|void} */ export const pushGroupProperty = function (g, undoable) { - const children = g.childNodes; - const len = children.length; - const xform = g.getAttribute('transform'); + const children = g.childNodes + const len = children.length + const xform = g.getAttribute('transform') - const glist = g.transform.baseVal; - const m = transformListToTransform(glist).matrix; + const glist = g.transform.baseVal + const m = transformListToTransform(glist).matrix - const batchCmd = new BatchCommand('Push group properties'); + const batchCmd = new BatchCommand('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", @@ -509,77 +509,77 @@ export const pushGroupProperty = function (g, undoable) { // and then for each child, if they do not have the attribute (or the value is 'inherit') // then set the child's attribute - const gangle = getRotationAngle(g); + const gangle = getRotationAngle(g) const gattrs = { filter: g.getAttribute('filter'), opacity: g.getAttribute('opacity') - }; - let gfilter; let gblur; let changes; - const drawing = svgCanvas.getDrawing(); + } + let gfilter; let gblur; let changes + const drawing = svgCanvas.getDrawing() for (let i = 0; i < len; i++) { - const elem = children[i]; + const elem = children[i] - if (elem.nodeType !== 1) { continue; } + if (elem.nodeType !== 1) { continue } 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; - svgCanvas.changeSelectedAttribute('opacity', newOpac, [ elem ]); + const newOpac = Math.round((elem.getAttribute('opacity') || 1) * gattrs.opacity * 100) / 100 + svgCanvas.changeSelectedAttribute('opacity', newOpac, [elem]) } if (gattrs.filter) { - let cblur = svgCanvas.getBlur(elem); - const origCblur = cblur; - if (!gblur) { gblur = svgCanvas.getBlur(g); } + let cblur = svgCanvas.getBlur(elem) + const origCblur = cblur + if (!gblur) { gblur = svgCanvas.getBlur(g) } if (cblur) { // Is this formula correct? - cblur = Number(gblur) + Number(cblur); + cblur = Number(gblur) + Number(cblur) } else if (cblur === 0) { - cblur = gblur; + 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); + gfilter = getRefElem(gattrs.filter) } else { // Clone the group's filter - gfilter = drawing.copyElem(gfilter); - findDefs().append(gfilter); + gfilter = drawing.copyElem(gfilter) + findDefs().append(gfilter) // const filterElem = getRefElem(gfilter); - const blurElem = getFeGaussianBlur(gfilter); + const blurElem = getFeGaussianBlur(gfilter) // Change this in future for different filters - const suffix = (blurElem?.tagName === 'feGaussianBlur') ? 'blur' : 'filter'; - gfilter.id = elem.id + '_' + suffix; - svgCanvas.changeSelectedAttribute('filter', 'url(#' + gfilter.id + ')', [ elem ]); + const suffix = (blurElem?.tagName === 'feGaussianBlur') ? 'blur' : 'filter' + gfilter.id = elem.id + '_' + suffix + svgCanvas.changeSelectedAttribute('filter', 'url(#' + gfilter.id + ')', [elem]) } } else { - gfilter = getRefElem(elem.getAttribute('filter')); + gfilter = getRefElem(elem.getAttribute('filter')) } // const filterElem = getRefElem(gfilter); - const blurElem = getFeGaussianBlur(gfilter); + const blurElem = getFeGaussianBlur(gfilter) // Update blur value if (cblur) { - svgCanvas.changeSelectedAttribute('stdDeviation', cblur, [ blurElem ]); - svgCanvas.setBlurOffsets(gfilter, cblur); + svgCanvas.changeSelectedAttribute('stdDeviation', cblur, [blurElem]) + svgCanvas.setBlurOffsets(gfilter, cblur) } } - let chtlist = elem.transform?.baseVal; + let chtlist = elem.transform?.baseVal // Don't process gradient transforms - if (elem.tagName.includes('Gradient')) { chtlist = null; } + if (elem.tagName.includes('Gradient')) { chtlist = null } // Hopefully not a problem to add this. Necessary for elements like - if (!chtlist) { continue; } + if (!chtlist) { continue } // Apparently can get get a transformlist, but we don't want it to have one! - if (elem.tagName === 'defs') { continue; } + if (elem.tagName === 'defs') { continue } if (glist.numberOfItems) { // TODO: if the group's transform is just a rotate, we can always transfer the @@ -596,88 +596,88 @@ export const pushGroupProperty = function (g, undoable) { // [Tr] = [Rg] [Rc] [Rc2_inv] // get group's rotation matrix (Rg) - const rgm = glist.getItem(0).matrix; + const rgm = glist.getItem(0).matrix // get child's rotation matrix (Rc) - let rcm = svgCanvas.getSvgRoot().createSVGMatrix(); - const cangle = getRotationAngle(elem); + let rcm = svgCanvas.getSvgRoot().createSVGMatrix() + const cangle = getRotationAngle(elem) if (cangle) { - rcm = chtlist.getItem(0).matrix; + rcm = chtlist.getItem(0).matrix } // get child's old center of rotation - const cbox = utilsGetBBox(elem); - const ceqm = transformListToTransform(chtlist).matrix; - const coldc = transformPoint(cbox.x + cbox.width / 2, cbox.y + cbox.height / 2, ceqm); + const cbox = utilsGetBBox(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; + const sangle = gangle + cangle // get child's rotation at the old center (Rc2_inv) - const r2 = svgCanvas.getSvgRoot().createSVGTransform(); - r2.setRotate(sangle, coldc.x, coldc.y); + const r2 = svgCanvas.getSvgRoot().createSVGTransform() + r2.setRotate(sangle, coldc.x, coldc.y) // calculate equivalent translate - const trm = matrixMultiply(rgm, rcm, r2.matrix.inverse()); + const trm = matrixMultiply(rgm, rcm, r2.matrix.inverse()) // set up tlist if (cangle) { - chtlist.removeItem(0); + chtlist.removeItem(0) } if (sangle) { if (chtlist.numberOfItems) { - chtlist.insertItemBefore(r2, 0); + chtlist.insertItemBefore(r2, 0) } else { - chtlist.appendItem(r2); + chtlist.appendItem(r2) } } if (trm.e || trm.f) { - const tr = svgCanvas.getSvgRoot().createSVGTransform(); - tr.setTranslate(trm.e, trm.f); + const tr = svgCanvas.getSvgRoot().createSVGTransform() + tr.setTranslate(trm.e, trm.f) if (chtlist.numberOfItems) { - chtlist.insertItemBefore(tr, 0); + chtlist.insertItemBefore(tr, 0) } else { - chtlist.appendItem(tr); + 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 oldxform = elem.getAttribute('transform') + changes = {} + changes.transform = oldxform || '' - const newxform = svgCanvas.getSvgRoot().createSVGTransform(); + const newxform = svgCanvas.getSvgRoot().createSVGTransform() // [ gm ] [ chm ] = [ chm ] [ gm' ] // [ gm' ] = [ chmInv ] [ gm ] [ chm ] - const chm = transformListToTransform(chtlist).matrix; - const chmInv = chm.inverse(); - const gm = matrixMultiply(chmInv, m, chm); - newxform.setMatrix(gm); - chtlist.appendItem(newxform); + const chm = transformListToTransform(chtlist).matrix + const chmInv = chm.inverse() + const gm = matrixMultiply(chmInv, m, chm) + newxform.setMatrix(gm) + chtlist.appendItem(newxform) } - const cmd = recalculateDimensions(elem); - if (cmd) { batchCmd.addSubCommand(cmd); } + 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(g, changes)); + changes = {} + changes.transform = xform + g.setAttribute('transform', '') + g.removeAttribute('transform') + batchCmd.addSubCommand(new ChangeElementCommand(g, changes)) } if (undoable && !batchCmd.isEmpty()) { - return batchCmd; + return batchCmd } - return undefined; -}; + return undefined +} /** * Converts selected/given `` or child SVG element to a group. @@ -687,153 +687,152 @@ export const pushGroupProperty = function (g, undoable) { * @returns {void} */ export const convertToGroup = function (elem) { - const selectedElements = svgCanvas.getSelectedElements(); + const selectedElements = svgCanvas.getSelectedElements() if (!elem) { - elem = selectedElements[0]; + elem = selectedElements[0] } - const $elem = elem; - const batchCmd = new BatchCommand(); - let ts; - const dataStorage = svgCanvas.getDataStorage(); + const $elem = elem + const batchCmd = new BatchCommand() + let ts + const dataStorage = svgCanvas.getDataStorage() if (dataStorage.has($elem, 'gsvg')) { // Use the gsvg as the new group - const svg = elem.firstChild; + const svg = elem.firstChild const pt = { x: Number(svg.getAttribute('x')), y: Number(svg.getAttribute('y')) - }; + } // $(elem.firstChild.firstChild).unwrap(); - const firstChild = elem.firstChild.firstChild; + const firstChild = elem.firstChild.firstChild if (firstChild) { - // eslint-disable-next-line no-unsanitized/property - firstChild.outerHTML = firstChild.innerHTML; + firstChild.outerHTML = firstChild.innerHTML } - dataStorage.remove(elem, 'gsvg'); + dataStorage.remove(elem, 'gsvg') - const tlist = elem.transform.baseVal; - const xform = svgCanvas.getSvgRoot().createSVGTransform(); - xform.setTranslate(pt.x, pt.y); - tlist.appendItem(xform); - recalculateDimensions(elem); - svgCanvas.call('selected', [ elem ]); + const tlist = elem.transform.baseVal + const xform = svgCanvas.getSvgRoot().createSVGTransform() + xform.setTranslate(pt.x, pt.y) + tlist.appendItem(xform) + recalculateDimensions(elem) + svgCanvas.call('selected', [elem]) } else if (dataStorage.has($elem, 'symbol')) { - elem = dataStorage.get($elem, 'symbol'); + elem = dataStorage.get($elem, 'symbol') - ts = $elem.getAttribute('transform'); + ts = $elem.getAttribute('transform') const pos = { x: Number($elem.getAttribute('x')), y: Number($elem.getAttribute('y')) - }; + } - const vb = elem.getAttribute('viewBox'); + const vb = elem.getAttribute('viewBox') if (vb) { - const nums = vb.split(' '); - pos.x -= Number(nums[0]); - pos.y -= Number(nums[1]); + const 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) + ')'; + ts += ' translate(' + (pos.x || 0) + ',' + (pos.y || 0) + ')' - const prev = $elem.previousElementSibling; + const prev = $elem.previousElementSibling // Remove element - batchCmd.addSubCommand(new RemoveElementCommand($elem, $elem.nextElementSibling, $elem.parentNode)); - $elem.remove(); + batchCmd.addSubCommand(new RemoveElementCommand($elem, $elem.nextElementSibling, $elem.parentNode)) + $elem.remove() // See if other elements reference this symbol - const svgContent = svgCanvas.getSvgContent(); + const svgContent = svgCanvas.getSvgContent() // const hasMore = svgContent.querySelectorAll('use:data(symbol)').length; // @todo review this logic - const hasMore = svgContent.querySelectorAll('use').length; + const hasMore = svgContent.querySelectorAll('use').length - const g = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'g'); - const childs = elem.childNodes; + const g = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'g') + const childs = elem.childNodes - let i; + let i for (i = 0; i < childs.length; i++) { - g.append(childs[i].cloneNode(true)); + g.append(childs[i].cloneNode(true)) } // Duplicate the gradients for Gecko, since they weren't included in the if (isGecko()) { - const svgElement = findDefs(); - const gradients = svgElement.querySelectorAll('linearGradient,radialGradient,pattern'); + const svgElement = findDefs() + const gradients = svgElement.querySelectorAll('linearGradient,radialGradient,pattern') for (let i = 0, im = gradients.length; im > i; i++) { - g.appendChild(gradients[i].cloneNode(true)); + g.appendChild(gradients[i].cloneNode(true)) } } if (ts) { - g.setAttribute('transform', ts); + g.setAttribute('transform', ts) } - const parent = elem.parentNode; + const parent = elem.parentNode - svgCanvas.uniquifyElems(g); + svgCanvas.uniquifyElems(g) // Put the dupe gradients back into (after uniquifying them) if (isGecko()) { - const svgElement = findDefs(); - const elements = g.querySelectorAll('linearGradient,radialGradient,pattern'); + const svgElement = findDefs() + const elements = g.querySelectorAll('linearGradient,radialGradient,pattern') for (let i = 0, im = elements.length; im > i; i++) { - svgElement.appendChild(elements[i]); + svgElement.appendChild(elements[i]) } } // now give the g itself a new id - g.id = svgCanvas.getNextId(); + g.id = svgCanvas.getNextId() - prev.after(g); + prev.after(g) if (parent) { if (!hasMore) { // remove symbol/svg element - const { nextSibling } = elem; - elem.remove(); - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); + const { nextSibling } = elem + elem.remove() + batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)) } - batchCmd.addSubCommand(new InsertElementCommand(g)); + batchCmd.addSubCommand(new InsertElementCommand(g)) } - svgCanvas.setUseData(g); + svgCanvas.setUseData(g) if (isGecko()) { - svgCanvas.convertGradients(findDefs()); + svgCanvas.convertGradients(findDefs()) } else { - svgCanvas.convertGradients(g); + svgCanvas.convertGradients(g) } // recalculate dimensions on the top-level children so that unnecessary transforms // are removed walkTreePost(g, function (n) { try { - recalculateDimensions(n); + recalculateDimensions(n) } catch (e) { - console.error(e); + console.error(e) } - }); + }) // Give ID for any visible element missing one - const visElems = g.querySelectorAll(svgCanvas.getVisElems()); + const visElems = g.querySelectorAll(svgCanvas.getVisElems()) Array.prototype.forEach.call(visElems, function (el) { - if (!el.id) { el.id = svgCanvas.getNextId(); } - }); + if (!el.id) { el.id = svgCanvas.getNextId() } + }) - svgCanvas.selectOnly([ g ]); + svgCanvas.selectOnly([g]) - const cm = pushGroupProperty(g, true); + const cm = pushGroupProperty(g, true) if (cm) { - batchCmd.addSubCommand(cm); + batchCmd.addSubCommand(cm) } - svgCanvas.addCommandToHistory(batchCmd); + svgCanvas.addCommandToHistory(batchCmd) } else { - console.warn('Unexpected element to ungroup:', elem); + console.warn('Unexpected element to ungroup:', elem) } -}; +} /** * Unwraps all the elements in a selected group (`g`) element. This requires @@ -842,72 +841,72 @@ export const convertToGroup = function (elem) { * @returns {void} */ export const ungroupSelectedElement = function () { - const selectedElements = svgCanvas.getSelectedElements(); - const dataStorage = svgCanvas.getDataStorage(); - let g = selectedElements[0]; + const selectedElements = svgCanvas.getSelectedElements() + const dataStorage = svgCanvas.getDataStorage() + let g = selectedElements[0] if (!g) { - return; + return } if (dataStorage.has(g, 'gsvg') || dataStorage.has(g, 'symbol')) { // Is svg, so actually convert to group - convertToGroup(g); - return; + convertToGroup(g) + return } if (g.tagName === 'use') { // Somehow doesn't have data set, so retrieve - const symbol = getElem(getHref(g).substr(1)); - dataStorage.put(g, 'symbol', symbol); - dataStorage.put(g, 'ref', symbol); - convertToGroup(g); - return; + const symbol = getElem(getHref(g).substr(1)) + dataStorage.put(g, 'symbol', symbol) + dataStorage.put(g, 'ref', symbol) + convertToGroup(g) + return } - const parentsA = getParents(g.parentNode, 'a'); + const parentsA = getParents(g.parentNode, 'a') if (parentsA?.length) { - g = parentsA[0]; + g = parentsA[0] } // Look for parent "a" if (g.tagName === 'g' || g.tagName === 'a') { - const batchCmd = new BatchCommand('Ungroup Elements'); - const cmd = pushGroupProperty(g, true); - if (cmd) { batchCmd.addSubCommand(cmd); } + const batchCmd = new BatchCommand('Ungroup Elements') + const cmd = pushGroupProperty(g, true) + if (cmd) { batchCmd.addSubCommand(cmd) } - const parent = g.parentNode; - const anchor = g.nextSibling; - const children = new Array(g.childNodes.length); + const parent = g.parentNode + const anchor = g.nextSibling + const children = new Array(g.childNodes.length) - let i = 0; + let i = 0 while (g.firstChild) { - const elem = g.firstChild; - const oldNextSibling = elem.nextSibling; - const oldParent = elem.parentNode; + 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(elem, nextSibling, oldParent)); - elem.remove(); - continue; + const { nextSibling } = elem + batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, oldParent)) + elem.remove() + continue } - children[i++] = parent.insertBefore(elem, anchor); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)); + children[i++] = parent.insertBefore(elem, anchor) + batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)) } // remove the group from the selection - svgCanvas.clearSelection(); + svgCanvas.clearSelection() // delete the group element (but make undo-able) - const gNextSibling = g.nextSibling; - g.remove(); - batchCmd.addSubCommand(new RemoveElementCommand(g, gNextSibling, parent)); + const gNextSibling = g.nextSibling + g.remove() + batchCmd.addSubCommand(new RemoveElementCommand(g, gNextSibling, parent)) - if (!batchCmd.isEmpty()) { svgCanvas.addCommandToHistory(batchCmd); } + if (!batchCmd.isEmpty()) { svgCanvas.addCommandToHistory(batchCmd) } // update selection - svgCanvas.addToSelection(children); + svgCanvas.addToSelection(children) } -}; +} /** * Updates the editor canvas width/height/position after a zoom has occurred. * @function module:svgcanvas.SvgCanvas#updateCanvas @@ -917,14 +916,14 @@ export const ungroupSelectedElement = function () { * @returns {module:svgcanvas.CanvasInfo} */ export const updateCanvas = function (w, h) { - svgCanvas.getSvgRoot().setAttribute('width', w); - svgCanvas.getSvgRoot().setAttribute('height', h); - const zoom = svgCanvas.getZoom(); - const bg = document.getElementById('canvasBackground'); - const oldX = Number(svgCanvas.getSvgContent().getAttribute('x')); - const oldY = Number(svgCanvas.getSvgContent().getAttribute('y')); - const x = ((w - this.contentW * zoom) / 2); - const y = ((h - this.contentH * zoom) / 2); + svgCanvas.getSvgRoot().setAttribute('width', w) + svgCanvas.getSvgRoot().setAttribute('height', h) + const zoom = svgCanvas.getZoom() + const bg = document.getElementById('canvasBackground') + const oldX = Number(svgCanvas.getSvgContent().getAttribute('x')) + const oldY = Number(svgCanvas.getSvgContent().getAttribute('y')) + const x = ((w - this.contentW * zoom) / 2) + const y = ((h - this.contentH * zoom) / 2) assignAttributes(svgCanvas.getSvgContent(), { width: this.contentW * zoom, @@ -932,24 +931,24 @@ export const updateCanvas = function (w, h) { x, y, viewBox: '0 0 ' + this.contentW + ' ' + this.contentH - }); + }) assignAttributes(bg, { width: svgCanvas.getSvgContent().getAttribute('width'), height: svgCanvas.getSvgContent().getAttribute('height'), x, y - }); + }) - const bgImg = getElem('background_image'); + const bgImg = getElem('background_image') if (bgImg) { assignAttributes(bgImg, { width: '100%', height: '100%' - }); + }) } - svgCanvas.selectorManager.selectorParentGroup.setAttribute('transform', 'translate(' + x + ',' + y + ')'); + svgCanvas.selectorManager.selectorParentGroup.setAttribute('transform', 'translate(' + x + ',' + y + ')') /** * Invoked upon updates to the canvas. @@ -968,9 +967,9 @@ export const updateCanvas = function (w, h) { * @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 }; -}; + ) + return { x, y, old_x: oldX, old_y: oldY, d_x: x - oldX, d_y: y - oldY } +} /** * Select the next/previous element within the current layer. * @function module:svgcanvas.SvgCanvas#cycleElement @@ -979,31 +978,31 @@ export const updateCanvas = function (w, h) { * @returns {void} */ export const cycleElement = function (next) { - const selectedElements = svgCanvas.getSelectedElements(); - const currentGroup = svgCanvas.getCurrentGroup(); - let num; - const curElem = selectedElements[0]; - let elem = false; - const allElems = getVisibleElements(currentGroup || svgCanvas.getCurrentDrawing().getCurrentLayer()); - if (!allElems.length) { return; } + const selectedElements = svgCanvas.getSelectedElements() + const currentGroup = svgCanvas.getCurrentGroup() + let num + const curElem = selectedElements[0] + let elem = false + const allElems = getVisibleElements(currentGroup || svgCanvas.getCurrentDrawing().getCurrentLayer()) + if (!allElems.length) { return } if (isNullish(curElem)) { - num = next ? allElems.length - 1 : 0; - elem = allElems[num]; + num = next ? allElems.length - 1 : 0 + elem = allElems[num] } else { - let i = allElems.length; + let i = allElems.length while (i--) { if (allElems[i] === curElem) { - num = next ? i - 1 : i + 1; + num = next ? i - 1 : i + 1 if (num >= allElems.length) { - num = 0; + num = 0 } else if (num < 0) { - num = allElems.length - 1; + num = allElems.length - 1 } - elem = allElems[num]; - break; + elem = allElems[num] + break } } } - svgCanvas.selectOnly([ elem ], true); - svgCanvas.call('selected', selectedElements); -}; + svgCanvas.selectOnly([elem], true) + svgCanvas.call('selected', selectedElements) +} diff --git a/src/svgcanvas/selection.js b/src/svgcanvas/selection.js index e22f4c0a..73d5c930 100644 --- a/src/svgcanvas/selection.js +++ b/src/svgcanvas/selection.js @@ -5,21 +5,21 @@ * @copyright 2011 Jeff Schiller */ -import { NS } from "./namespaces.js"; +import { NS } from './namespaces.js' import { getBBox, getStrokedBBoxDefaultVisible -} from "./utilities.js"; +} from './utilities.js' import { transformPoint, transformListToTransform, rectsIntersect -} from "./math.js"; -import * as hstry from "./history.js"; -import { getClosest } from "../editor/components/jgraduate/Util.js"; +} from './math.js' +import * as hstry from './history.js' +import { getClosest } from '../editor/components/jgraduate/Util.js' -const { BatchCommand } = hstry; -let svgCanvas = null; +const { BatchCommand } = hstry +let svgCanvas = null /** * @function module:selection.init @@ -27,8 +27,8 @@ let svgCanvas = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; -}; + svgCanvas = canvas +} /** * Clears the selection. The 'selected' handler is then optionally called. @@ -38,20 +38,20 @@ export const init = function (canvas) { * @fires module:selection.SvgCanvas#event:selected */ export const clearSelectionMethod = function (noCall) { - const selectedElements = svgCanvas.getSelectedElements(); + const selectedElements = svgCanvas.getSelectedElements() selectedElements.forEach((elem) => { if (!elem) { - return; + return } - svgCanvas.selectorManager.releaseSelector(elem); - }); - svgCanvas?.setEmptySelectedElements(); + svgCanvas.selectorManager.releaseSelector(elem) + }) + svgCanvas?.setEmptySelectedElements() if (!noCall) { - svgCanvas.call("selected", svgCanvas.getSelectedElements()); + svgCanvas.call('selected', svgCanvas.getSelectedElements()) } -}; +} /** * Adds a list of elements to the selection. The 'selected' handler is then called. @@ -60,56 +60,56 @@ export const clearSelectionMethod = function (noCall) { * @fires module:selection.SvgCanvas#event:selected */ export const addToSelectionMethod = function (elemsToAdd, showGrips) { - const selectedElements = svgCanvas.getSelectedElements(); + const selectedElements = svgCanvas.getSelectedElements() if (!elemsToAdd.length) { - return; + return } // find the first null in our selectedElements array - let firstNull = 0; + let firstNull = 0 while (firstNull < selectedElements.length) { if (selectedElements[firstNull] === null) { - break; + break } - ++firstNull; + ++firstNull } // now add each element consecutively - let i = elemsToAdd.length; + let i = elemsToAdd.length while (i--) { - let elem = elemsToAdd[i]; + let elem = elemsToAdd[i] if (!elem || !elem.getBBox) { - continue; + continue } - if (elem.tagName === "a" && elem.childNodes.length === 1) { + if (elem.tagName === 'a' && elem.childNodes.length === 1) { // Make "a" element's child be the selected element - elem = elem.firstChild; + elem = elem.firstChild } // if it's not already there, add it if (!selectedElements.includes(elem)) { - selectedElements[firstNull] = elem; + selectedElements[firstNull] = elem // only the first selectedBBoxes element is ever used in the codebase these days // if (j === 0) selectedBBoxes[0] = utilsGetBBox(elem); - firstNull++; - const sel = svgCanvas.selectorManager.requestSelector(elem); + firstNull++ + const sel = svgCanvas.selectorManager.requestSelector(elem) if (selectedElements.length > 1) { - sel.showGrips(false); + sel.showGrips(false) } } } if (!selectedElements.length) { - return; + return } - svgCanvas.call("selected", selectedElements); + svgCanvas.call('selected', selectedElements) if (selectedElements.length === 1) { svgCanvas.selectorManager .requestSelector(selectedElements[0]) - .showGrips(showGrips); + .showGrips(showGrips) } // make sure the elements are in the correct order @@ -117,63 +117,63 @@ export const addToSelectionMethod = function (elemsToAdd, showGrips) { selectedElements.sort(function (a, b) { if (a && b && a.compareDocumentPosition) { - return 3 - (b.compareDocumentPosition(a) & 6); + return 3 - (b.compareDocumentPosition(a) & 6) } if (!a) { - return 1; + return 1 } - return 0; - }); + return 0 + }) // Make sure first elements are not null while (!selectedElements[0]) { - selectedElements.shift(0); + selectedElements.shift(0) } -}; +} /** * @name module:svgcanvas.SvgCanvas#getMouseTarget * @type {module:path.EditorContext#getMouseTarget} */ export const getMouseTargetMethod = function (evt) { if (!evt) { - return null; + return null } - let mouseTarget = evt.target; + let mouseTarget = evt.target // if it was a , Opera and WebKit return the SVGElementInstance if (mouseTarget.correspondingUseElement) { - mouseTarget = 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" + [NS.MATH, NS.HTML].includes(mouseTarget.namespaceURI) && + mouseTarget.id !== 'svgcanvas' ) { - while (mouseTarget.nodeName !== "foreignObject") { - mouseTarget = mouseTarget.parentNode; + while (mouseTarget.nodeName !== 'foreignObject') { + mouseTarget = mouseTarget.parentNode if (!mouseTarget) { - return svgCanvas.getSvgRoot(); + return svgCanvas.getSvgRoot() } } } // Get the desired mouseTarget with jQuery selector-fu // If it's root-like, select the root - const currentLayer = svgCanvas.getCurrentDrawing().getCurrentLayer(); - const svgRoot = svgCanvas.getSvgRoot(); - const container = svgCanvas.getDOMContainer(); - const content = svgCanvas.getSvgContent(); - if ([ svgRoot, container, content, currentLayer ].includes(mouseTarget)) { - return svgCanvas.getSvgRoot(); + const currentLayer = svgCanvas.getCurrentDrawing().getCurrentLayer() + const svgRoot = svgCanvas.getSvgRoot() + const container = svgCanvas.getDOMContainer() + const content = svgCanvas.getSvgContent() + if ([svgRoot, container, content, currentLayer].includes(mouseTarget)) { + return svgCanvas.getSvgRoot() } // If it's a selection grip, return the grip parent - if (getClosest(mouseTarget.parentNode, "#selectorParentGroup")) { + if (getClosest(mouseTarget.parentNode, '#selectorParentGroup')) { // While we could instead have just returned mouseTarget, // this makes it easier to indentify as being a selector grip - return svgCanvas.selectorManager.selectorParentGroup; + return svgCanvas.selectorManager.selectorParentGroup } while ( @@ -181,11 +181,11 @@ export const getMouseTargetMethod = function (evt) { svgCanvas.getCurrentGroup() || currentLayer ) ) { - mouseTarget = mouseTarget.parentNode; + mouseTarget = mouseTarget.parentNode } - return mouseTarget; -}; + return mouseTarget +} /** * @typedef {module:svgcanvas.ExtensionMouseDownStatus|module:svgcanvas.ExtensionMouseUpStatus|module:svgcanvas.ExtensionIDsUpdatedStatus|module:locale.ExtensionLocaleData[]|void} module:svgcanvas.ExtensionStatus * @tutorial ExtensionDocs @@ -218,24 +218,24 @@ export const runExtensionsMethod = function ( returnArray, nameFilter ) { - let result = returnArray ? [] : false; - for (const [ name, ext ] of Object.entries(svgCanvas.getExtensions())) { + let result = returnArray ? [] : false + for (const [name, ext] of Object.entries(svgCanvas.getExtensions())) { if (nameFilter && !nameFilter(name)) { - return; + return } if (ext && action in ext) { - if (typeof vars === "function") { - vars = vars(name); // ext, action + if (typeof vars === 'function') { + vars = vars(name) // ext, action } if (returnArray) { - result.push(ext[action](vars)); + result.push(ext[action](vars)) } else { - result = ext[action](vars); + result = ext[action](vars) } } } - return result; -}; + return result +} /** * Get all elements that have a BBox (excludes ``, ``, etc). @@ -247,18 +247,18 @@ export const runExtensionsMethod = function ( */ export const getVisibleElementsAndBBoxes = function (parent) { if (!parent) { - const svgContent = svgCanvas.getSvgContent(); - parent = svgContent.children; // Prevent layers from being included + const svgContent = svgCanvas.getSvgContent() + parent = svgContent.children // Prevent layers from being included } - const contentElems = []; - const elements = parent.children; + const contentElems = [] + const elements = parent.children Array.from(elements).forEach((elem) => { if (elem.getBBox) { - contentElems.push({ elem, bbox: getStrokedBBoxDefaultVisible([ elem ]) }); + contentElems.push({ elem, bbox: getStrokedBBoxDefaultVisible([elem]) }) } - }); - return contentElems.reverse(); -}; + }) + return contentElems.reverse() +} /** * This method sends back an array or a NodeList full of elements that @@ -273,55 +273,55 @@ export const getVisibleElementsAndBBoxes = function (parent) { * @returns {Element[]|NodeList} Bbox elements */ export const getIntersectionListMethod = function (rect) { - const zoom = svgCanvas.getZoom(); + const zoom = svgCanvas.getZoom() if (!svgCanvas.getRubberBox()) { - return null; + return null } const parent = svgCanvas.getCurrentGroup() || - svgCanvas.getCurrentDrawing().getCurrentLayer(); + svgCanvas.getCurrentDrawing().getCurrentLayer() - let rubberBBox; + let rubberBBox if (!rect) { - rubberBBox = getBBox(svgCanvas.getRubberBox()); + rubberBBox = getBBox(svgCanvas.getRubberBox()) const bb = svgCanvas.getSvgContent().createSVGRect(); - [ "x", "y", "width", "height", "top", "right", "bottom", "left" ].forEach( + ['x', 'y', 'width', 'height', 'top', 'right', 'bottom', 'left'].forEach( (o) => { - bb[o] = rubberBBox[o] / zoom; + bb[o] = rubberBBox[o] / zoom } - ); - rubberBBox = bb; + ) + rubberBBox = bb } else { - rubberBBox = svgCanvas.getSvgContent().createSVGRect(); - rubberBBox.x = rect.x; - rubberBBox.y = rect.y; - rubberBBox.width = rect.width; - rubberBBox.height = rect.height; + rubberBBox = svgCanvas.getSvgContent().createSVGRect() + rubberBBox.x = rect.x + rubberBBox.y = rect.y + rubberBBox.width = rect.width + rubberBBox.height = rect.height } - const resultList = []; + const resultList = [] if (svgCanvas.getCurBBoxes().length === 0) { // Cache all bboxes - svgCanvas.setCurBBoxes(getVisibleElementsAndBBoxes(parent)); + svgCanvas.setCurBBoxes(getVisibleElementsAndBBoxes(parent)) } - let i = svgCanvas.getCurBBoxes().length; + let i = svgCanvas.getCurBBoxes().length while (i--) { - const curBBoxes = svgCanvas.getCurBBoxes(); + const curBBoxes = svgCanvas.getCurBBoxes() if (!rubberBBox.width) { - continue; + continue } if (rectsIntersect(rubberBBox, curBBoxes[i].bbox)) { - resultList.push(curBBoxes[i].elem); + 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; -}; + return resultList +} /** * @typedef {PlainObject} ElementAndBBox @@ -336,13 +336,13 @@ export const getIntersectionListMethod = function (rect) { * @returns {void} */ export const groupSvgElem = function (elem) { - const dataStorage = svgCanvas.getDataStorage(); - const g = document.createElementNS(NS.SVG, "g"); - elem.replaceWith(g); - g.appendChild(elem); - dataStorage.put(g, "gsvg", elem); - g.id = svgCanvas.getNextId(); -}; + const dataStorage = svgCanvas.getDataStorage() + const g = document.createElementNS(NS.SVG, 'g') + elem.replaceWith(g) + g.appendChild(elem) + dataStorage.put(g, 'gsvg', elem) + g.id = svgCanvas.getNextId() +} /** * Runs the SVG Document through the sanitizer and then updates its paths. @@ -351,16 +351,16 @@ export const groupSvgElem = function (elem) { * @returns {void} */ export const prepareSvg = function (newDoc) { - svgCanvas.sanitizeSvg(newDoc.documentElement); + svgCanvas.sanitizeSvg(newDoc.documentElement) // convert paths into absolute commands - const paths = [ ...newDoc.getElementsByTagNameNS(NS.SVG, "path") ]; + const paths = [...newDoc.getElementsByTagNameNS(NS.SVG, 'path')] paths.forEach((path) => { - const convertedPath = svgCanvas.pathActions.convertPath(path); - path.setAttribute("d", convertedPath); - svgCanvas.pathActions.fixEnd(path); - }); -}; + const convertedPath = svgCanvas.pathActions.convertPath(path) + path.setAttribute('d', convertedPath) + svgCanvas.pathActions.fixEnd(path) + }) +} /** * Removes any old rotations if present, prepends a new rotation at the @@ -372,21 +372,21 @@ export const prepareSvg = function (newDoc) { * @returns {void} */ export const setRotationAngle = function (val, preventUndo) { - const selectedElements = svgCanvas.getSelectedElements(); + const selectedElements = svgCanvas.getSelectedElements() // 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; - const cy = bbox.y + bbox.height / 2; - const tlist = elem.transform.baseVal; + val = Number.parseFloat(val) + const elem = selectedElements[0] + const oldTransform = elem.getAttribute('transform') + const bbox = getBBox(elem) + const cx = bbox.x + bbox.width / 2 + const cy = bbox.y + bbox.height / 2 + const tlist = elem.transform.baseVal // only remove the real rotational transform if present (i.e. at index=0) if (tlist.numberOfItems > 0) { - const xform = tlist.getItem(0); + const xform = tlist.getItem(0) if (xform.type === 4) { - tlist.removeItem(0); + tlist.removeItem(0) } } // find Rnc and insert it @@ -395,33 +395,33 @@ export const setRotationAngle = function (val, preventUndo) { cx, cy, transformListToTransform(tlist).matrix - ); - const Rnc = svgCanvas.getSvgRoot().createSVGTransform(); - Rnc.setRotate(val, center.x, center.y); + ) + const Rnc = svgCanvas.getSvgRoot().createSVGTransform() + Rnc.setRotate(val, center.x, center.y) if (tlist.numberOfItems) { - tlist.insertItemBefore(Rnc, 0); + tlist.insertItemBefore(Rnc, 0) } else { - tlist.appendItem(Rnc); + tlist.appendItem(Rnc) } } else if (tlist.numberOfItems === 0) { - elem.removeAttribute("transform"); + 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"); + const newTransform = elem.getAttribute('transform') if (oldTransform) { - elem.setAttribute("transform", oldTransform); + elem.setAttribute('transform', oldTransform) } else { - elem.removeAttribute("transform"); + elem.removeAttribute('transform') } svgCanvas.changeSelectedAttribute( - "transform", + 'transform', newTransform, selectedElements - ); - svgCanvas.call("changed", selectedElements); + ) + svgCanvas.call('changed', selectedElements) } // const pointGripContainer = getElem('pathpointgrip_container'); // if (elem.nodeName === 'path' && pointGripContainer) { @@ -429,10 +429,10 @@ export const setRotationAngle = function (val, preventUndo) { // } const selector = svgCanvas.selectorManager.requestSelector( selectedElements[0] - ); - selector.resize(); - svgCanvas.getSelector().updateGripCursors(val); -}; + ) + selector.resize() + svgCanvas.getSelector().updateGripCursors(val) +} /** * Runs `recalculateDimensions` on the selected elements, @@ -443,19 +443,19 @@ export const setRotationAngle = function (val, preventUndo) { */ export const recalculateAllSelectedDimensions = function () { const text = - svgCanvas.getCurrentResizeMode() === "none" ? "position" : "size"; - const batchCmd = new BatchCommand(text); - const selectedElements = svgCanvas.getSelectedElements(); + svgCanvas.getCurrentResizeMode() === 'none' ? 'position' : 'size' + const batchCmd = new BatchCommand(text) + const selectedElements = svgCanvas.getSelectedElements() selectedElements.forEach((elem) => { - const cmd = svgCanvas.recalculateDimensions(elem); + const cmd = svgCanvas.recalculateDimensions(elem) if (cmd) { - batchCmd.addSubCommand(cmd); + batchCmd.addSubCommand(cmd) } - }); + }) if (!batchCmd.isEmpty()) { - svgCanvas.addCommandToHistory(batchCmd); - svgCanvas.call("changed", selectedElements); + svgCanvas.addCommandToHistory(batchCmd) + svgCanvas.call('changed', selectedElements) } -}; +} diff --git a/src/svgcanvas/svg-exec.js b/src/svgcanvas/svg-exec.js index 39176125..f63bf2e5 100644 --- a/src/svgcanvas/svg-exec.js +++ b/src/svgcanvas/svg-exec.js @@ -5,36 +5,36 @@ * @copyright 2011 Jeff Schiller */ -import { jsPDF } from 'jspdf/dist/jspdf.es.min.js'; -import 'svg2pdf.js/dist/svg2pdf.es.js'; -import html2canvas from 'html2canvas'; -import * as hstry from './history.js'; +import { jsPDF as JsPDF } from 'jspdf/dist/jspdf.es.min.js' +import 'svg2pdf.js/dist/svg2pdf.es.js' +import html2canvas from 'html2canvas' +import * as hstry from './history.js' import { text2xml, cleanupElement, findDefs, getHref, preventClickDefault, toXml, getStrokedBBoxDefaultVisible, encode64, createObjectURL, dataURLToObjectURL, walkTree, getBBox as utilsGetBBox -} from './utilities.js'; +} from './utilities.js' import { transformPoint, transformListToTransform -} from './math.js'; +} from './math.js' import { convertUnit, shortFloat, convertToNum -} from '../common/units.js'; -import { isGecko, isChrome, isWebkit } from '../common/browser.js'; -import * as pathModule from './path.js'; -import { NS } from './namespaces.js'; -import * as draw from './draw.js'; +} from '../common/units.js' +import { isGecko, isChrome, isWebkit } from '../common/browser.js' +import * as pathModule from './path.js' +import { NS } from './namespaces.js' +import * as draw from './draw.js' import { recalculateDimensions -} from './recalculate.js'; -import { getParents, getClosest } from '../editor/components/jgraduate/Util.js'; +} from './recalculate.js' +import { getParents, getClosest } from '../editor/components/jgraduate/Util.js' const { InsertElementCommand, RemoveElementCommand, ChangeElementCommand, BatchCommand -} = hstry; +} = hstry -let svgCanvas = null; +let svgCanvas = null /** * @function module:svg-exec.init @@ -42,8 +42,8 @@ let svgCanvas = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; -}; + svgCanvas = canvas +} /** * Main function to set up the SVG content for output. @@ -54,52 +54,52 @@ export const svgCanvasToString = function () { // keep calling it until there are none to remove while (svgCanvas.removeUnusedDefElems() > 0) { } // eslint-disable-line no-empty - svgCanvas.pathActions.clear(true); + svgCanvas.pathActions.clear(true) // Keep SVG-Edit comment on top - const childNodesElems = svgCanvas.getSvgContent().childNodes; + const childNodesElems = svgCanvas.getSvgContent().childNodes childNodesElems.forEach(function (node, i) { if (i && node.nodeType === 8 && node.data.includes('Created with')) { - svgCanvas.getSvgContent().firstChild.before(node); + svgCanvas.getSvgContent().firstChild.before(node) } - }); + }) // Move out of in-group editing mode if (svgCanvas.getCurrentGroup()) { - draw.leaveContext(); - svgCanvas.selectOnly([ svgCanvas.getCurrentGroup() ]); + draw.leaveContext() + svgCanvas.selectOnly([svgCanvas.getCurrentGroup()]) } - const nakedSvgs = []; + const nakedSvgs = [] // Unwrap gsvg if it has no special attributes (only id and style) - const gsvgElems = svgCanvas.getSvgContent().querySelectorAll('g[data-gsvg]'); + const gsvgElems = svgCanvas.getSvgContent().querySelectorAll('g[data-gsvg]') Array.prototype.forEach.call(gsvgElems, function (element) { - const attrs = element.attributes; - let len = attrs.length; + const attrs = element.attributes + let len = attrs.length for (let i = 0; i < len; i++) { if (attrs[i].nodeName === 'id' || attrs[i].nodeName === 'style') { - len--; + len-- } } // No significant attributes, so ungroup if (len <= 0) { - const svg = element.firstChild; - nakedSvgs.push(svg); - element.replaceWith(svg); + const svg = element.firstChild + nakedSvgs.push(svg) + element.replaceWith(svg) } - }); - const output = svgCanvas.svgToString(svgCanvas.getSvgContent(), 0); + }) + const output = svgCanvas.svgToString(svgCanvas.getSvgContent(), 0) // Rewrap gsvg if (nakedSvgs.length) { Array.prototype.forEach.call(nakedSvgs, function (el) { - svgCanvas.groupSvgElem(el); - }); + svgCanvas.groupSvgElem(el) + }) } - return output; -}; + return output +} /** * Sub function ran on each SVG element to convert it to a string as desired. @@ -109,27 +109,27 @@ export const svgCanvasToString = function () { * @returns {string} The given element as an SVG tag */ export const svgToString = function (elem, indent) { - const curConfig = svgCanvas.getCurConfig(); - const nsMap = svgCanvas.getNsMap(); - const out = []; - const unit = curConfig.baseUnit; - const unitRe = new RegExp('^-?[\\d\\.]+' + unit + '$'); + const curConfig = svgCanvas.getCurConfig() + const nsMap = svgCanvas.getNsMap() + const out = [] + const unit = curConfig.baseUnit + const unitRe = new RegExp('^-?[\\d\\.]+' + unit + '$') if (elem) { - cleanupElement(elem); - const attrs = [ ...elem.attributes ]; - const childs = elem.childNodes; + cleanupElement(elem) + const attrs = [...elem.attributes] + const childs = elem.childNodes attrs.sort((a, b) => { - return a.name > b.name ? -1 : 1; - }); + return a.name > b.name ? -1 : 1 + }) - for (let i = 0; i < indent; i++) { out.push(' '); } - out.push('<'); out.push(elem.nodeName); + for (let i = 0; i < indent; i++) { out.push(' ') } + out.push('<'); out.push(elem.nodeName) if (elem.id === 'svgcontent') { // Process root element separately - const res = svgCanvas.getResolution(); + const res = svgCanvas.getResolution() - const vb = ''; + 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') { @@ -143,76 +143,76 @@ export const svgToString = function (elem, indent) { // } if (unit !== 'px') { - res.w = convertUnit(res.w, unit) + unit; - res.h = convertUnit(res.h, unit) + unit; + 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 + '"'); + out.push(' width="' + res.w + '" height="' + res.h + '"' + vb + ' xmlns="' + NS.SVG + '"') - const nsuris = {}; + const nsuris = {} // Check elements for namespaces, add if found - const csElements = elem.querySelectorAll('*'); - const cElements = Array.prototype.slice.call(csElements); - cElements.push(elem); + const csElements = elem.querySelectorAll('*') + const cElements = Array.prototype.slice.call(csElements) + cElements.push(elem) Array.prototype.forEach.call(cElements, function (el) { // const el = this; // for some elements have no attribute - const uri = el.namespaceURI; + const uri = el.namespaceURI if (uri && !nsuris[uri] && nsMap[uri] && nsMap[uri] !== 'xmlns' && nsMap[uri] !== 'xml') { - nsuris[uri] = true; - out.push(' xmlns:' + nsMap[uri] + '="' + uri + '"'); + nsuris[uri] = true + out.push(' xmlns:' + nsMap[uri] + '="' + uri + '"') } if (el.attributes.length > 0) { - for (const [ , attr ] of Object.entries(el.attributes)) { - const u = attr.namespaceURI; + for (const [, attr] of Object.entries(el.attributes)) { + const u = attr.namespaceURI if (u && !nsuris[u] && nsMap[u] !== 'xmlns' && nsMap[u] !== 'xml') { - nsuris[u] = true; - out.push(' xmlns:' + nsMap[u] + '="' + u + '"'); + nsuris[u] = true + out.push(' xmlns:' + nsMap[u] + '="' + u + '"') } } } - }); + }) - let i = attrs.length; - const attrNames = [ 'width', 'height', 'xmlns', 'x', 'y', 'viewBox', 'id', 'overflow' ]; + 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); + const attr = attrs[i] + const attrVal = toXml(attr.value) // Namespaces have already been dealt with, so skip - if (attr.nodeName.startsWith('xmlns:')) { continue; } + if (attr.nodeName.startsWith('xmlns:')) { continue } // only serialize attributes we don't use internally if (attrVal !== '' && !attrNames.includes(attr.localName) && (!attr.namespaceURI || nsMap[attr.namespaceURI])) { - out.push(' '); - out.push(attr.nodeName); out.push('="'); - out.push(attrVal); out.push('"'); + out.push(' ') + out.push(attr.nodeName); out.push('="') + out.push(attrVal); out.push('"') } } } else { // Skip empty defs - if (elem.nodeName === 'defs' && !elem.firstChild) { return ''; } + if (elem.nodeName === 'defs' && !elem.firstChild) { return '' } - const mozAttrs = [ '-moz-math-font-style', '_moz-math-font-style' ]; + 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); + const attr = attrs[i] + let attrVal = toXml(attr.value) // remove bogus attributes added by Gecko - if (mozAttrs.includes(attr.localName)) { continue; } + 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; } + 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 = svgCanvas.pathActions.convertPath(elem, true); } + if (attrVal.startsWith('pointer-events')) { continue } + if (attr.localName === 'class' && attrVal.startsWith('se_')) { continue } + out.push(' ') + if (attr.localName === 'd') { attrVal = svgCanvas.pathActions.convertPath(elem, true) } if (!isNaN(attrVal)) { - attrVal = shortFloat(attrVal); + attrVal = shortFloat(attrVal) } else if (unitRe.test(attrVal)) { - attrVal = shortFloat(attrVal) + unit; + attrVal = shortFloat(attrVal) + unit } // Embed images when saving @@ -222,67 +222,67 @@ export const svgToString = function (elem, indent) { svgCanvas.getSvgOptionImages() && svgCanvas.getSvgOptionImages() === 'embed' ) { - const img = svgCanvas.getEncodableImages(attrVal); - if (img) { attrVal = img; } + const img = svgCanvas.getEncodableImages(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('"'); + out.push(attr.nodeName); out.push('="') + out.push(attrVal); out.push('"') } } } } if (elem.hasChildNodes()) { - out.push('>'); - indent++; - let bOneLine = false; + out.push('>') + indent++ + let bOneLine = false for (let i = 0; i < childs.length; i++) { - const child = childs.item(i); + const child = childs.item(i) switch (child.nodeType) { - case 1: // element node - out.push('\n'); - out.push(svgCanvas.svgToString(child, indent)); - break; - case 3: { // text node - const 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; + case 1: // element node + out.push('\n') + out.push(svgCanvas.svgToString(child, indent)) + break + case 3: { // text node + const 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 } - indent--; + indent-- if (!bOneLine) { - out.push('\n'); - for (let i = 0; i < indent; i++) { out.push(' '); } + out.push('\n') + for (let i = 0; i < indent; i++) { out.push(' ') } } - out.push('</'); out.push(elem.nodeName); out.push('>'); + out.push('</'); out.push(elem.nodeName); out.push('>') } else { - out.push('/>'); + out.push('/>') } } - return out.join(''); -}; // end svgToString() + return out.join('') +} // end svgToString() /** * This function sets the current drawing as the input SVG XML. @@ -298,209 +298,208 @@ export const svgToString = function (elem, indent) { * unsuccessful, `true` otherwise. */ export const setSvgString = function (xmlString, preventUndo) { - const curConfig = svgCanvas.getCurConfig(); - const dataStorage = svgCanvas.getDataStorage(); + const curConfig = svgCanvas.getCurConfig() + const dataStorage = svgCanvas.getDataStorage() try { // convert string into XML document - const newDoc = text2xml(xmlString); + const newDoc = text2xml(xmlString) if (newDoc.firstElementChild && newDoc.firstElementChild.namespaceURI !== NS.SVG) { - return false; + return false } - svgCanvas.prepareSvg(newDoc); + svgCanvas.prepareSvg(newDoc) - const batchCmd = new BatchCommand('Change Source'); + const batchCmd = new BatchCommand('Change Source') // remove old svg document - const { nextSibling } = svgCanvas.getSvgContent(); + const { nextSibling } = svgCanvas.getSvgContent() - svgCanvas.getSvgContent().remove(); - const oldzoom = svgCanvas.getSvgContent(); - batchCmd.addSubCommand(new RemoveElementCommand(oldzoom, nextSibling, svgCanvas.getSvgRoot())); + svgCanvas.getSvgContent().remove() + const oldzoom = svgCanvas.getSvgContent() + batchCmd.addSubCommand(new RemoveElementCommand(oldzoom, nextSibling, svgCanvas.getSvgRoot())) // set new svg document // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() if (svgCanvas.getDOMDocument().adoptNode) { - svgCanvas.setSvgContent(svgCanvas.getDOMDocument().adoptNode(newDoc.documentElement)); + svgCanvas.setSvgContent(svgCanvas.getDOMDocument().adoptNode(newDoc.documentElement)) } else { - svgCanvas.setSvgContent(svgCanvas.getDOMDocument().importNode(newDoc.documentElement, true)); + svgCanvas.setSvgContent(svgCanvas.getDOMDocument().importNode(newDoc.documentElement, true)) } - svgCanvas.getSvgRoot().append(svgCanvas.getSvgContent()); - const content = svgCanvas.getSvgContent(); + svgCanvas.getSvgRoot().append(svgCanvas.getSvgContent()) + const content = svgCanvas.getSvgContent() - svgCanvas.current_drawing_ = new draw.Drawing(svgCanvas.getSvgContent(), svgCanvas.getIdPrefix()); + svgCanvas.current_drawing_ = new draw.Drawing(svgCanvas.getSvgContent(), svgCanvas.getIdPrefix()) // retrieve or set the nonce - const nonce = svgCanvas.getCurrentDrawing().getNonce(); + const nonce = svgCanvas.getCurrentDrawing().getNonce() if (nonce) { - svgCanvas.call('setnonce', nonce); + svgCanvas.call('setnonce', nonce) } else { - svgCanvas.call('unsetnonce'); + svgCanvas.call('unsetnonce') } // change image href vals if possible - const elements = content.querySelectorAll('image'); + const elements = content.querySelectorAll('image') Array.prototype.forEach.call(elements, function (image) { - preventClickDefault(image); - const val = svgCanvas.getHref(image); + preventClickDefault(image) + const val = svgCanvas.getHref(image) 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=(.*?);/) // const m = val.match(/svgedit_url=(?<url>.*?);/); if (m) { - const url = decodeURIComponent(m[1]); + const url = decodeURIComponent(m[1]) // const url = decodeURIComponent(m.groups.url); - const iimg = new Image(); - iimg.addEventListener("load", () => { - image.setAttributeNS(NS.XLINK, 'xlink:href', url); - }); - iimg.src = url; + const iimg = new Image() + iimg.addEventListener('load', () => { + image.setAttributeNS(NS.XLINK, 'xlink:href', url) + }) + iimg.src = url } } // Add to encodableImages if it loads - svgCanvas.embedImage(val); + svgCanvas.embedImage(val) } - }); + }) // Duplicate id replace changes - const nodes = content.querySelectorAll('[id]'); - const ids = {}; - const totalNodes = nodes.length; + const nodes = content.querySelectorAll('[id]') + const ids = {} + const totalNodes = nodes.length - for(let i=0; i<totalNodes; i++) { - const currentId = nodes[i].id ? nodes[i].id : "undefined"; - if(isNaN(ids[currentId])) { - ids[currentId] = 0; + for (let i = 0; i < totalNodes; i++) { + const currentId = nodes[i].id ? nodes[i].id : 'undefined' + if (isNaN(ids[currentId])) { + ids[currentId] = 0 } - ids[currentId]++; + ids[currentId]++ } - Object.entries(ids).forEach(([ key, value ]) => { + Object.entries(ids).forEach(([key, value]) => { if (value > 1) { - const nodes = content.querySelectorAll('[id="'+key+'"]'); - for(let i=1; i<nodes.length; i++) { - nodes[i].setAttribute('id', svgCanvas.getNextId()); + const nodes = content.querySelectorAll('[id="' + key + '"]') + for (let i = 1; i < nodes.length; i++) { + nodes[i].setAttribute('id', svgCanvas.getNextId()) } } - }); - + }) // Wrap child SVGs in group elements - const svgElements = content.querySelectorAll('svg'); + const svgElements = content.querySelectorAll('svg') Array.prototype.forEach.call(svgElements, function (element) { // Skip if it's in a <defs> - if (getClosest(element.parentNode, 'defs')) { return; } + if (getClosest(element.parentNode, 'defs')) { return } - svgCanvas.uniquifyElems(element); + svgCanvas.uniquifyElems(element) // Check if it already has a gsvg group - const pa = element.parentNode; + const pa = element.parentNode if (pa.childNodes.length === 1 && pa.nodeName === 'g') { - dataStorage.put(pa, 'gsvg', element); - pa.id = pa.id || svgCanvas.getNextId(); + dataStorage.put(pa, 'gsvg', element) + pa.id = pa.id || svgCanvas.getNextId() } else { - svgCanvas.groupSvgElem(element); + svgCanvas.groupSvgElem(element) } - }); + }) // For Firefox: Put all paint elems in defs if (isGecko()) { - const svgDefs = findDefs(); - const findElems = content.querySelectorAll('linearGradient, radialGradient, pattern'); + const svgDefs = findDefs() + const findElems = content.querySelectorAll('linearGradient, radialGradient, pattern') Array.prototype.forEach.call(findElems, function (ele) { - svgDefs.appendChild(ele); - }); + svgDefs.appendChild(ele) + }) } // Set ref element for <use> elements // TODO: This should also be done if the object is re-added through "redo" - svgCanvas.setUseData(content); + svgCanvas.setUseData(content) - svgCanvas.convertGradients(content); + svgCanvas.convertGradients(content) const attrs = { id: 'svgcontent', overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden' - }; + } - let percs = false; + let percs = false // determine proper size if (content.getAttribute('viewBox')) { - const viBox = content.getAttribute('viewBox'); - const vb = viBox.split(' '); - attrs.width = vb[2]; - attrs.height = vb[3]; + const viBox = content.getAttribute('viewBox') + const vb = viBox.split(' ') + attrs.width = vb[2] + attrs.height = vb[3] // handle content that doesn't have a viewBox } else { - [ 'width', 'height' ].forEach(function (dim) { + ['width', 'height'].forEach(function (dim) { // Set to 100 if not given - const val = content.getAttribute(dim) || '100%'; + const val = content.getAttribute(dim) || '100%' if (String(val).substr(-1) === '%') { // Use user units if percentage given - percs = true; + percs = true } else { - attrs[dim] = convertToNum(dim, val); + attrs[dim] = convertToNum(dim, val) } - }); + }) } // identify layers - draw.identifyLayers(); + draw.identifyLayers() // Give ID for any visible layer children missing one - const chiElems = content.children; + const chiElems = content.children Array.prototype.forEach.call(chiElems, function (chiElem) { - const visElems = chiElem.querySelectorAll(svgCanvas.getVisElems()); + const visElems = chiElem.querySelectorAll(svgCanvas.getVisElems()) Array.prototype.forEach.call(visElems, function (elem) { - if (!elem.id) { elem.id = svgCanvas.getNextId(); } - }); - }); + if (!elem.id) { elem.id = svgCanvas.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; + 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; } + if (attrs.width <= 0) { attrs.width = 100 } + if (attrs.height <= 0) { attrs.height = 100 } - for (const [ key, value ] of Object.entries(attrs)) { - content.setAttribute(key, value); + for (const [key, value] of Object.entries(attrs)) { + content.setAttribute(key, value) } - svgCanvas.contentW = attrs.width; - svgCanvas.contentH = attrs.height; + svgCanvas.contentW = attrs.width + svgCanvas.contentH = attrs.height - batchCmd.addSubCommand(new InsertElementCommand(svgCanvas.getSvgContent())); + batchCmd.addSubCommand(new InsertElementCommand(svgCanvas.getSvgContent())) // update root to the correct size - const width = content.getAttribute('width'); - const height = content.getAttribute('height'); - const changes = { width: width, height: height }; - batchCmd.addSubCommand(new ChangeElementCommand(svgCanvas.getSvgRoot(), changes)); + const width = content.getAttribute('width') + const height = content.getAttribute('height') + const changes = { width: width, height: height } + batchCmd.addSubCommand(new ChangeElementCommand(svgCanvas.getSvgRoot(), changes)) // reset zoom - svgCanvas.setZoom(1); + svgCanvas.setZoom(1) - svgCanvas.clearSelection(); - pathModule.clearData(); - svgCanvas.getSvgRoot().append(svgCanvas.selectorManager.selectorParentGroup); + svgCanvas.clearSelection() + pathModule.clearData() + svgCanvas.getSvgRoot().append(svgCanvas.selectorManager.selectorParentGroup) - if (!preventUndo) svgCanvas.addCommandToHistory(batchCmd); - svgCanvas.call('changed', [ svgCanvas.getSvgContent() ]); + if (!preventUndo) svgCanvas.addCommandToHistory(batchCmd) + svgCanvas.call('changed', [svgCanvas.getSvgContent()]) } catch (e) { - console.error(e); - return false; + console.error(e) + return false } - return true; -}; + return true +} /** * This function imports the input SVG XML as a `<symbol>` in the `<defs>`, then adds a @@ -517,120 +516,120 @@ export const setSvgString = function (xmlString, preventUndo) { * was obtained */ export const importSvgString = function (xmlString) { - const dataStorage = svgCanvas.getDataStorage(); - let j; let ts; let useEl; + const dataStorage = svgCanvas.getDataStorage() + let j; let ts; let useEl try { // Get unique ID - const uid = encode64(xmlString.length + xmlString).substr(0, 32); + const uid = encode64(xmlString.length + xmlString).substr(0, 32) - let useExisting = false; + let useExisting = false // Look for symbol and make sure symbol exists in image if (svgCanvas.getImportIds(uid) && svgCanvas.getImportIds(uid).symbol) { - const parents = getParents(svgCanvas.getImportIds(uid).symbol, '#svgroot'); + const parents = getParents(svgCanvas.getImportIds(uid).symbol, '#svgroot') if (parents?.length) { - useExisting = true; + useExisting = true } } - const batchCmd = new BatchCommand('Import Image'); - let symbol; + const batchCmd = new BatchCommand('Import Image') + let symbol if (useExisting) { - symbol = svgCanvas.getImportIds(uid).symbol; - ts = svgCanvas.getImportIds(uid).xform; + symbol = svgCanvas.getImportIds(uid).symbol + ts = svgCanvas.getImportIds(uid).xform } else { // convert string into XML document - const newDoc = text2xml(xmlString); + const newDoc = text2xml(xmlString) - svgCanvas.prepareSvg(newDoc); + svgCanvas.prepareSvg(newDoc) // import new svg document into our document // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() const svg = svgCanvas.getDOMDocument().adoptNode ? svgCanvas.getDOMDocument().adoptNode(newDoc.documentElement) - : svgCanvas.getDOMDocument().importNode(newDoc.documentElement, true); + : svgCanvas.getDOMDocument().importNode(newDoc.documentElement, true) - svgCanvas.uniquifyElems(svg); + svgCanvas.uniquifyElems(svg) - const innerw = convertToNum('width', svg.getAttribute('width')); - const innerh = convertToNum('height', svg.getAttribute('height')); - const innervb = svg.getAttribute('viewBox'); + const innerw = convertToNum('width', svg.getAttribute('width')) + const innerh = convertToNum('height', svg.getAttribute('height')) + const innervb = svg.getAttribute('viewBox') // if no explicit viewbox, create one out of the width and height - const vb = innervb ? innervb.split(' ') : [ 0, 0, innerw, innerh ]; + const vb = innervb ? innervb.split(' ') : [0, 0, innerw, innerh] for (j = 0; j < 4; ++j) { - vb[j] = Number(vb[j]); + vb[j] = Number(vb[j]) } // TODO: properly handle preserveAspectRatio const // canvasw = +svgContent.getAttribute('width'), - canvash = Number(svgCanvas.getSvgContent().getAttribute('height')); + canvash = Number(svgCanvas.getSvgContent().getAttribute('height')) // imported content should be 1/3 of the canvas on its largest dimension - ts = innerh > innerw ? 'scale(' + (canvash / 3) / vb[3] + ')' : 'scale(' + (canvash / 3) / vb[2] + ')'; + ts = innerh > innerw ? 'scale(' + (canvash / 3) / vb[3] + ')' : 'scale(' + (canvash / 3) / vb[2] + ')' // Hack to make recalculateDimensions understand how to scale - ts = 'translate(0) ' + ts + ' translate(0)'; + ts = 'translate(0) ' + ts + ' translate(0)' - symbol = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'symbol'); - const defs = findDefs(); + symbol = svgCanvas.getDOMDocument().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. - const elements = svg.querySelectorAll('linearGradient, radialGradient, pattern'); + const elements = svg.querySelectorAll('linearGradient, radialGradient, pattern') Array.prototype.forEach.call(elements, function (el) { - defs.appendChild(el); - }); + defs.appendChild(el) + }) } while (svg.firstChild) { - const first = svg.firstChild; - symbol.append(first); + const first = svg.firstChild + symbol.append(first) } - const attrs = svg.attributes; + const attrs = svg.attributes for (const attr of attrs) { // Ok for `NamedNodeMap` - symbol.setAttribute(attr.nodeName, attr.value); + symbol.setAttribute(attr.nodeName, attr.value) } - symbol.id = svgCanvas.getNextId(); + symbol.id = svgCanvas.getNextId() // Store data svgCanvas.setImportIds(uid, { symbol, xform: ts - }); + }) - findDefs().append(symbol); - batchCmd.addSubCommand(new InsertElementCommand(symbol)); + findDefs().append(symbol) + batchCmd.addSubCommand(new InsertElementCommand(symbol)) } - useEl = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'use'); - useEl.id = svgCanvas.getNextId(); + useEl = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'use') + useEl.id = svgCanvas.getNextId() svgCanvas.setHref(useEl, '#' + symbol.id); - (svgCanvas.getCurrentGroup() || svgCanvas.getCurrentDrawing().getCurrentLayer()).append(useEl); - batchCmd.addSubCommand(new InsertElementCommand(useEl)); - svgCanvas.clearSelection(); + (svgCanvas.getCurrentGroup() || svgCanvas.getCurrentDrawing().getCurrentLayer()).append(useEl) + batchCmd.addSubCommand(new InsertElementCommand(useEl)) + svgCanvas.clearSelection() - useEl.setAttribute('transform', ts); - recalculateDimensions(useEl); - dataStorage.put(useEl, 'symbol', symbol); - dataStorage.put(useEl, 'ref', symbol); - svgCanvas.addToSelection([ useEl ]); + useEl.setAttribute('transform', ts) + recalculateDimensions(useEl) + dataStorage.put(useEl, 'symbol', symbol) + dataStorage.put(useEl, 'ref', symbol) + svgCanvas.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; // } - svgCanvas.addCommandToHistory(batchCmd); - svgCanvas.call('changed', [ svgCanvas.getSvgContent() ]); + svgCanvas.addCommandToHistory(batchCmd) + svgCanvas.call('changed', [svgCanvas.getSvgContent()]) } catch (e) { - console.error(e); - return null; + console.error(e) + return null } // we want to return the element so we can automatically select it - return useEl; -}; + return useEl +} /** * Function to run when image data is found. * @callback module:svgcanvas.ImageEmbeddedCallback @@ -647,31 +646,31 @@ export const embedImage = function (src) { // Todo: Remove this Promise in favor of making an async/await `Image.load` utility return new Promise(function (resolve, reject) { // load in the image and once it's loaded, get the dimensions - const imgI = new Image(); - imgI.addEventListener("load", (e) => { + const imgI = new Image() + imgI.addEventListener('load', (e) => { // create a canvas the same size as the raster image - const cvs = document.createElement('canvas'); - cvs.width = e.currentTarget.width; - cvs.height = e.currentTarget.height; + const cvs = document.createElement('canvas') + cvs.width = e.currentTarget.width + cvs.height = e.currentTarget.height // load the raster image into the canvas - cvs.getContext('2d').drawImage(e.currentTarget, 0, 0); + cvs.getContext('2d').drawImage(e.currentTarget, 0, 0) // retrieve the data: URL try { - let urldata = ';svgedit_url=' + encodeURIComponent(src); - urldata = cvs.toDataURL().replace(';base64', urldata + ';base64'); - svgCanvas.setEncodableImages(src, urldata); + let urldata = ';svgedit_url=' + encodeURIComponent(src) + urldata = cvs.toDataURL().replace(';base64', urldata + ';base64') + svgCanvas.setEncodableImages(src, urldata) } catch (e) { - svgCanvas.setEncodableImages(src, false); + svgCanvas.setEncodableImages(src, false) } - svgCanvas.setGoodImage(src); - resolve(svgCanvas.getEncodableImages(src)); - }); - imgI.addEventListener("error", (e) => { - reject(`error loading image: ${e.currentTarget.attributes.src.value}`); - }); - imgI.setAttribute('src', src); - }); -}; + svgCanvas.setGoodImage(src) + resolve(svgCanvas.getEncodableImages(src)) + }) + imgI.addEventListener('error', (e) => { + reject(new Error(`error loading image: ${e.currentTarget.attributes.src.value}`)) + }) + imgI.setAttribute('src', src) + }) +} /** * @typedef {PlainObject} module:svgcanvas.IssuesAndCodes @@ -683,35 +682,35 @@ export const embedImage = function (src) { * Codes only is useful for locale-independent detection. * @returns {module:svgcanvas.IssuesAndCodes} */ -function getIssues() { - const uiStrings = svgCanvas.getUIStrings(); +function getIssues () { + const uiStrings = svgCanvas.getUIStrings() // remove the selected outline before serializing - svgCanvas.clearSelection(); + svgCanvas.clearSelection() // Check for known CanVG issues - const issues = []; - const issueCodes = []; + const issues = [] + const issueCodes = [] // Selector and notice const issueList = { feGaussianBlur: uiStrings.exportNoBlur, foreignObject: uiStrings.exportNoforeignObject, '[stroke-dasharray]': uiStrings.exportNoDashArray - }; - const content = svgCanvas.getSvgContent(); + } + const content = svgCanvas.getSvgContent() // Add font/text check if Canvas Text API is not implemented if (!('font' in document.querySelector('CANVAS').getContext('2d'))) { - issueList.text = uiStrings.exportNoText; + issueList.text = uiStrings.exportNoText } - for (const [ sel, descr ] of Object.entries(issueList)) { + for (const [sel, descr] of Object.entries(issueList)) { if (content.querySelectorAll(sel).length) { - issueCodes.push(sel); - issues.push(descr); + issueCodes.push(sel) + issues.push(descr) } } - return { issues, issueCodes }; + return { issues, issueCodes } } /** * @typedef {PlainObject} module:svgcanvas.ImageExportedResults @@ -741,53 +740,60 @@ function getIssues() { * @returns {Promise<module:svgcanvas.ImageExportedResults>} Resolves to {@link module:svgcanvas.ImageExportedResults} */ export const 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 = svgCanvas.svgCanvasToString(); + const type = imgType === 'ICO' ? 'BMP' : (imgType || 'PNG') + const mimeType = 'image/' + type.toLowerCase() + const { issues, issueCodes } = getIssues() + const svg = svgCanvas.svgCanvasToString() - const iframe = document.createElement('iframe'); - iframe.onload = function() { - const iframedoc=iframe.contentDocument||iframe.contentWindow.document; - const ele = svgCanvas.getSvgContent(); - const cln = ele.cloneNode(true); - iframedoc.body.appendChild(cln); - setTimeout(function(){ + const iframe = document.createElement('iframe') + iframe.onload = function () { + const iframedoc = iframe.contentDocument || iframe.contentWindow.document + const ele = svgCanvas.getSvgContent() + const cln = ele.cloneNode(true) + iframedoc.body.appendChild(cln) + setTimeout(function () { // eslint-disable-next-line promise/catch-or-return html2canvas(iframedoc.body, { useCORS: true, allowTaint: true }).then((canvas) => { return new Promise((resolve) => { - const dataURLType = type.toLowerCase(); + const dataURLType = type.toLowerCase() const datauri = quality ? canvas.toDataURL('image/' + dataURLType, quality) - : canvas.toDataURL('image/' + dataURLType); - iframe.parentNode.removeChild(iframe); - let bloburl; + : canvas.toDataURL('image/' + dataURLType) + iframe.parentNode.removeChild(iframe) + let bloburl - function done() { + function done () { const obj = { - datauri, bloburl, svg, issues, issueCodes, type: imgType, - mimeType, quality, exportWindowName - }; - if (!opts.avoidEvent) { - svgCanvas.call('exported', obj); + datauri, + bloburl, + svg, + issues, + issueCodes, + type: imgType, + mimeType, + quality, + exportWindowName } - resolve(obj); + if (!opts.avoidEvent) { + svgCanvas.call('exported', obj) + } + resolve(obj) } if (canvas.toBlob) { canvas.toBlob((blob) => { - bloburl = createObjectURL(blob); - done(); - }, mimeType, quality); - return; + bloburl = createObjectURL(blob) + done() + }, mimeType, quality) + return } - bloburl = dataURLToObjectURL(datauri); - done(); - }); - }); - }, 1000); - }; - document.body.appendChild(iframe); -}; + bloburl = dataURLToObjectURL(datauri) + done() + }) + }) + }, 1000) + } + document.body.appendChild(iframe) +} /** * @typedef {void|"save"|"arraybuffer"|"blob"|"datauristring"|"dataurlstring"|"dataurlnewwindow"|"datauri"|"dataurl"} external:jsPDF.OutputType @@ -825,41 +831,41 @@ export const exportPDF = async ( exportWindowName, outputType = isChrome() ? 'save' : undefined ) => { - const res = svgCanvas.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 - const iframe = document.createElement('iframe'); - iframe.onload = function() { - const iframedoc=iframe.contentDocument||iframe.contentWindow.document; - const ele = svgCanvas.getSvgContent(); - const cln = ele.cloneNode(true); - iframedoc.body.appendChild(cln); - setTimeout(function(){ + const res = svgCanvas.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 + const iframe = document.createElement('iframe') + iframe.onload = function () { + const iframedoc = iframe.contentDocument || iframe.contentWindow.document + const ele = svgCanvas.getSvgContent() + const cln = ele.cloneNode(true) + iframedoc.body.appendChild(cln) + setTimeout(function () { // eslint-disable-next-line promise/catch-or-return html2canvas(iframedoc.body, { useCORS: true, allowTaint: true }).then((canvas) => { - const imgData = canvas.toDataURL('image/png'); - const doc = new jsPDF({ + const imgData = canvas.toDataURL('image/png') + const doc = new JsPDF({ orientation: orientation, unit: unit, - format: [ res.w, res.h ] - }); - const docTitle = svgCanvas.getDocumentTitle(); + format: [res.w, res.h] + }) + const docTitle = svgCanvas.getDocumentTitle() doc.setProperties({ title: docTitle - }); - doc.addImage(imgData, 'PNG', 0, 0, res.w, res.h); - iframe.parentNode.removeChild(iframe); - const { issues, issueCodes } = getIssues(); - outputType = outputType || 'dataurlstring'; - const obj = { issues, issueCodes, exportWindowName, outputType }; - obj.output = doc.output(outputType, outputType === 'save' ? (exportWindowName || 'svg.pdf') : undefined); - svgCanvas.call('exportedPDF', obj); - return obj; - }); - }, 1000); - }; - document.body.appendChild(iframe); -}; + }) + doc.addImage(imgData, 'PNG', 0, 0, res.w, res.h) + iframe.parentNode.removeChild(iframe) + const { issues, issueCodes } = getIssues() + outputType = outputType || 'dataurlstring' + const obj = { issues, issueCodes, exportWindowName, outputType } + obj.output = doc.output(outputType, outputType === 'save' ? (exportWindowName || 'svg.pdf') : undefined) + svgCanvas.call('exportedPDF', obj) + return obj + }) + }, 1000) + } + document.body.appendChild(iframe) +} /** * Ensure each element has a unique ID. * @function module:svgcanvas.SvgCanvas#uniquifyElems @@ -867,7 +873,7 @@ export const exportPDF = async ( * @returns {void} */ export const uniquifyElemsMethod = function (g) { - const ids = {}; + const ids = {} // TODO: Handle markers and connectors. These are not yet re-identified properly // as their referring elements do not get remapped. // @@ -876,7 +882,7 @@ export const uniquifyElemsMethod = function (g) { // // 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' ]; + const refElems = ['filter', 'linearGradient', 'pattern', 'radialGradient', 'symbol', 'textPath', 'use'] walkTree(g, function (n) { // if it's an element node @@ -886,73 +892,73 @@ export const uniquifyElemsMethod = function (g) { // 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: null, attrs: [], hrefs: [] } } - ids[n.id].elem = n; + ids[n.id].elem = n } // now search for all attributes on this element that might refer // to other elements - svgCanvas.getrefAttrs().forEach(function(attr){ - const attrnode = n.getAttributeNode(attr); + svgCanvas.getrefAttrs().forEach(function (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 = svgCanvas.getUrlFromAttr(attrnode.value); - const refid = url ? url.substr(1) : null; + const url = svgCanvas.getUrlFromAttr(attrnode.value) + const 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] = { elem: null, attrs: [], hrefs: [] } } - ids[refid].attrs.push(attrnode); + ids[refid].attrs.push(attrnode) } } - }); + }) // check xlink:href now - const href = svgCanvas.getHref(n); + const href = svgCanvas.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); + const refid = href.substr(1) if (refid) { if (!(refid in ids)) { // add this id to our map - ids[refid] = { elem: null, attrs: [], hrefs: [] }; + ids[refid] = { elem: null, attrs: [], hrefs: [] } } - ids[refid].hrefs.push(n); + ids[refid].hrefs.push(n) } } } - }); + }) // in ids, we now have a map of ids, elements and attributes, let's re-identify for (const oldid in ids) { - if (!oldid) { continue; } - const { elem } = ids[oldid]; + if (!oldid) { continue } + const { elem } = ids[oldid] if (elem) { - const newid = svgCanvas.getNextId(); + const newid = svgCanvas.getNextId() // assign element its new id - elem.id = newid; + elem.id = newid // remap all url() attributes - const { attrs } = ids[oldid]; - let j = attrs.length; + const { attrs } = ids[oldid] + let j = attrs.length while (j--) { - const attr = attrs[j]; - attr.ownerElement.setAttribute(attr.name, 'url(#' + newid + ')'); + const attr = attrs[j] + attr.ownerElement.setAttribute(attr.name, 'url(#' + newid + ')') } // remap all href attributes - const hreffers = ids[oldid].hrefs; - let k = hreffers.length; + const hreffers = ids[oldid].hrefs + let k = hreffers.length while (k--) { - const hreffer = hreffers[k]; - svgCanvas.setHref(hreffer, '#' + newid); + const hreffer = hreffers[k] + svgCanvas.setHref(hreffer, '#' + newid) } } } -}; +} /** * Assigns reference data for each use element. @@ -961,25 +967,25 @@ export const uniquifyElemsMethod = function (g) { * @returns {void} */ export const setUseDataMethod = function (parent) { - let elems = parent; + let elems = parent if (parent.tagName !== 'use') { // elems = elems.find('use'); - elems = elems.querySelectorAll('use'); + elems = elems.querySelectorAll('use') } Array.prototype.forEach.call(elems, function (el, _) { - const dataStorage = svgCanvas.getDataStorage(); - const id = svgCanvas.getHref(el).substr(1); - const refElem = svgCanvas.getElem(id); - if (!refElem) { return; } - dataStorage.put(el, 'ref', refElem); + const dataStorage = svgCanvas.getDataStorage() + const id = svgCanvas.getHref(el).substr(1) + const refElem = svgCanvas.getElem(id) + if (!refElem) { return } + dataStorage.put(el, 'ref', refElem) if (refElem.tagName === 'symbol' || refElem.tagName === 'svg') { - dataStorage.put(el, 'symbol', refElem); - dataStorage.put(el, 'ref', refElem); + dataStorage.put(el, 'symbol', refElem) + dataStorage.put(el, 'ref', refElem) } - }); -}; + }) +} /** * Looks at DOM elements inside the `<defs>` to see if they are referred to, @@ -988,53 +994,53 @@ export const setUseDataMethod = function (parent) { * @returns {Integer} The number of elements that were removed */ export const removeUnusedDefElemsMethod = function () { - const defs = svgCanvas.getSvgContent().getElementsByTagNameNS(NS.SVG, 'defs'); - if (!defs || !defs.length) { return 0; } + const defs = svgCanvas.getSvgContent().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 defelemUses = [] + let numRemoved = 0 + const attrs = ['fill', 'stroke', 'filter', 'marker-start', 'marker-mid', 'marker-end'] + const alen = attrs.length - const allEls = svgCanvas.getSvgContent().getElementsByTagNameNS(NS.SVG, '*'); - const allLen = allEls.length; + const allEls = svgCanvas.getSvgContent().getElementsByTagNameNS(NS.SVG, '*') + const allLen = allEls.length - let i; let j; + let i; let j for (i = 0; i < allLen; i++) { - const el = allEls[i]; + const el = allEls[i] for (j = 0; j < alen; j++) { - const ref = svgCanvas.getUrlFromAttr(el.getAttribute(attrs[j])); + const ref = svgCanvas.getUrlFromAttr(el.getAttribute(attrs[j])) if (ref) { - defelemUses.push(ref.substr(1)); + defelemUses.push(ref.substr(1)) } } // gradients can refer to other gradients - const href = getHref(el); + const href = getHref(el) if (href && href.startsWith('#')) { - defelemUses.push(href.substr(1)); + defelemUses.push(href.substr(1)) } } Array.prototype.forEach.call(defs, function (def, i) { - const defelems = def.querySelectorAll('linearGradient, radialGradient, filter, marker, svg, symbol'); - i = defelems.length; + const defelems = def.querySelectorAll('linearGradient, radialGradient, filter, marker, svg, symbol') + i = defelems.length while (i--) { - const defelem = defelems[i]; - const { id } = defelem; + const defelem = defelems[i] + const { id } = defelem if (!defelemUses.includes(id)) { // Not found, so remove (but remember) - svgCanvas.setRemovedElements(id, defelem); - defelem.remove(); - numRemoved++; + svgCanvas.setRemovedElements(id, defelem) + defelem.remove() + numRemoved++ } } - }); + }) - return numRemoved; -}; + return numRemoved +} /** * Converts gradients from userSpaceOnUse to objectBoundingBox. * @function module:svgcanvas.SvgCanvas#convertGradients @@ -1042,63 +1048,63 @@ export const removeUnusedDefElemsMethod = function () { * @returns {void} */ export const convertGradientsMethod = function (elem) { - let elems = elem.querySelectorAll('linearGradient, radialGradient'); + let elems = elem.querySelectorAll('linearGradient, radialGradient') if (!elems.length && isWebkit()) { // Bug in webkit prevents regular *Gradient selector search elems = Array.prototype.filter.call(elem.querySelectorAll('*'), function (curThis) { - return (curThis.tagName.includes('Gradient')); - }); + return (curThis.tagName.includes('Gradient')) + }) } Array.prototype.forEach.call(elems, function (grad) { if (grad.getAttribute('gradientUnits') === 'userSpaceOnUse') { - const svgContent = svgCanvas.getSvgContent(); + const svgContent = svgCanvas.getSvgContent() // TODO: Support more than one element with this ref by duplicating parent grad - let fillStrokeElems = svgContent.querySelectorAll('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]'); + let fillStrokeElems = svgContent.querySelectorAll('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]') if (!fillStrokeElems.length) { - const tmpFillStrokeElems = svgContent.querySelectorAll('[*|href="#' + grad.id + '"]'); + const tmpFillStrokeElems = svgContent.querySelectorAll('[*|href="#' + grad.id + '"]') if (!tmpFillStrokeElems.length) { - return; + return } else { - if((tmpFillStrokeElems[0].tagName === "linearGradient" || tmpFillStrokeElems[0].tagName === "radialGradient") && tmpFillStrokeElems[0].getAttribute('gradientUnits') === 'userSpaceOnUse') { - fillStrokeElems = svgContent.querySelectorAll('[fill="url(#' + tmpFillStrokeElems[0].id + ')"],[stroke="url(#' + tmpFillStrokeElems[0].id + ')"]'); + if ((tmpFillStrokeElems[0].tagName === 'linearGradient' || tmpFillStrokeElems[0].tagName === 'radialGradient') && tmpFillStrokeElems[0].getAttribute('gradientUnits') === 'userSpaceOnUse') { + fillStrokeElems = svgContent.querySelectorAll('[fill="url(#' + tmpFillStrokeElems[0].id + ')"],[stroke="url(#' + tmpFillStrokeElems[0].id + ')"]') } else { - return; + return } } } // get object's bounding box - const bb = utilsGetBBox(fillStrokeElems[0]); + const bb = utilsGetBBox(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; } + if (!bb) { return } if (grad.tagName === 'linearGradient') { const gCoords = { x1: grad.getAttribute('x1'), y1: grad.getAttribute('y1'), x2: grad.getAttribute('x2'), y2: grad.getAttribute('y2') - }; + } // If has transform, convert - const tlist = grad.gradientTransform.baseVal; + 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); + 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'); + gCoords.x1 = pt1.x + gCoords.y1 = pt1.y + gCoords.x2 = pt2.x + gCoords.y2 = pt2.y + grad.removeAttribute('gradientTransform') } - grad.setAttribute('x1', (gCoords.x1 - bb.x) / bb.width); - grad.setAttribute('y1', (gCoords.y1 - bb.y) / bb.height); - grad.setAttribute('x2', (gCoords.x2 - bb.x) / bb.width); - grad.setAttribute('y2', (gCoords.y2 - bb.y) / bb.height); - grad.removeAttribute('gradientUnits'); + grad.setAttribute('x1', (gCoords.x1 - bb.x) / bb.width) + grad.setAttribute('y1', (gCoords.y1 - bb.y) / bb.height) + grad.setAttribute('x2', (gCoords.x2 - bb.x) / bb.width) + grad.setAttribute('y2', (gCoords.y2 - bb.y) / bb.height) + grad.removeAttribute('gradientUnits') } } - }); -}; + }) +} diff --git a/src/svgcanvas/svgcanvas.js b/src/svgcanvas/svgcanvas.js index 6428d38c..926cd153 100644 --- a/src/svgcanvas/svgcanvas.js +++ b/src/svgcanvas/svgcanvas.js @@ -8,45 +8,45 @@ * */ -import { Canvg as canvg } from 'canvg'; -import 'pathseg'; // SVGPathSeg Polyfill (see https://github.com/progers/pathseg) +import { Canvg as canvg } from 'canvg' +import 'pathseg' // SVGPathSeg Polyfill (see https://github.com/progers/pathseg) -import * as pathModule from './path.js'; -import * as history from './history.js'; -import * as draw from './draw.js'; +import * as pathModule from './path.js' +import * as history from './history.js' +import * as draw from './draw.js' import { init as pasteInit, pasteElementsMethod -} from './paste-elem.js'; -import { svgRootElement } from './svgroot.js'; +} from './paste-elem.js' +import { svgRootElement } from './svgroot.js' import { init as undoInit, changeSelectedAttributeNoUndoMethod, changeSelectedAttributeMethod -} from './undo.js'; +} from './undo.js' import { init as selectionInit, clearSelectionMethod, addToSelectionMethod, getMouseTargetMethod, getIntersectionListMethod, runExtensionsMethod, groupSvgElem, prepareSvg, recalculateAllSelectedDimensions, setRotationAngle -} from './selection.js'; +} from './selection.js' import { init as textActionsInit, textActionsMethod -} from './text-actions.js'; +} from './text-actions.js' import { init as eventInit, mouseMoveEvent, mouseUpEvent, mouseOutEvent, dblClickEvent, mouseDownEvent, DOMMouseScrollEvent -} from './event.js'; -import { init as jsonInit, getJsonFromSvgElements, addSVGElementsFromJson } from './json.js'; -import * as elemGetSet from './elem-get-set.js'; +} from './event.js' +import { init as jsonInit, getJsonFromSvgElements, addSVGElementsFromJson } from './json.js' +import * as elemGetSet from './elem-get-set.js' import { init as selectedElemInit, moveToTopSelectedElem, moveToBottomSelectedElem, moveUpDownSelected, moveSelectedElements, cloneSelectedElements, alignSelectedElements, deleteSelectedElements, copySelectedElements, groupSelectedElements, pushGroupProperty, ungroupSelectedElement, cycleElement, updateCanvas -} from './selected-elem.js'; +} from './selected-elem.js' import { init as blurInit, setBlurNoUndo, setBlurOffsets, setBlur -} from './blur-event.js'; -import { sanitizeSvg } from './sanitize.js'; -import { getReverseNS, NS } from './namespaces.js'; +} from './blur-event.js' +import { sanitizeSvg } from './sanitize.js' +import { getReverseNS, NS } from './namespaces.js' import { assignAttributes, cleanupElement, getElem, getUrlFromAttr, findDefs, getHref, setHref, getRefElem, getRotationAngle, @@ -54,48 +54,47 @@ import { getVisibleElements, init as utilsInit, getBBox as utilsGetBBox, getStrokedBBoxDefaultVisible, isNullish, blankPageObjectURL, $id, $qa, $qq, getFeGaussianBlur, stringToHTML, insertChildAtIndex -} from './utilities.js'; +} from './utilities.js' import { matrixMultiply, hasMatrixTransform, transformListToTransform -} from './math.js'; +} from './math.js' import { convertToNum, init as unitsInit, getTypeMap -} from '../common/units.js'; +} from '../common/units.js' import { svgCanvasToString, svgToString, setSvgString, exportPDF, setUseDataMethod, init as svgInit, importSvgString, embedImage, rasterExport, uniquifyElemsMethod, removeUnusedDefElemsMethod, convertGradientsMethod -} from './svg-exec.js'; +} from './svg-exec.js' import { remapElement, init as coordsInit -} from './coords.js'; +} from './coords.js' import { recalculateDimensions, init as recalculateInit -} from './recalculate.js'; +} from './recalculate.js' import { getSelectorManager, Selector, init as selectInit -} from './select.js'; +} from './select.js' import { clearSvgContentElementInit, init as clearInit -} from './clear.js'; +} from './clear.js' import { getClosest, getParents, mergeDeep -} from '../editor/components/jgraduate/Util.js'; +} from '../editor/components/jgraduate/Util.js' -import dataStorage from './dataStorage.js'; +import dataStorage from './dataStorage.js' -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 THRESHOLD_DIST = 0.8; -const STEP_COUNT = 10; -const CLIPBOARD_ID = 'svgedit_clipboard'; +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 THRESHOLD_DIST = 0.8 +const STEP_COUNT = 10 +const CLIPBOARD_ID = 'svgedit_clipboard' /** * The main SvgCanvas class that manages all SVG-related functions. @@ -107,78 +106,78 @@ class SvgCanvas { * @param {HTMLElement} container - The container HTML element that should hold the SVG root element * @param {module:SVGeditor.configObj.curConfig} config - An object that contains configuration data */ - constructor(container, config) { + constructor (container, config) { // imported function made available as methods - this.initializeSvgCanvasMethods(); - const { pathActions } = pathModule; + this.initializeSvgCanvasMethods() + const { pathActions } = pathModule // initialize class variables - this.saveOptions = { round_digits: 5 }; // Object with save options - this.importIds = {}; // Object with IDs for imported files, to see if one was already added - this.extensions = {}; // Object to contain all included extensions - this.removedElements = {}; // Map of deleted reference elements - this.started = false; // Boolean indicating whether or not a draw action has been this.started - this.startTransform = null; // String with an element's initial transform attribute value - this.currentMode = 'select'; // String indicating the current editor mode - this.currentResizeMode = 'none'; // String with the current direction in which an element is being resized - this.justSelected = null; // The DOM element that was just selected - this.rubberBox = null; // DOM element for selection rectangle drawn by the user - this.curBBoxes = []; // Array of current BBoxes, used in getIntersectionList(). - this.lastClickPoint = null; // Canvas point for the most recent right click - this.events = {}; // Object to contain editor event names and callback functions - this.rootSctm = null; // Root Current Transformation Matrix in user units - this.drawnPath = null; + this.saveOptions = { round_digits: 5 } // Object with save options + this.importIds = {} // Object with IDs for imported files, to see if one was already added + this.extensions = {} // Object to contain all included extensions + this.removedElements = {} // Map of deleted reference elements + this.started = false // Boolean indicating whether or not a draw action has been this.started + this.startTransform = null // String with an element's initial transform attribute value + this.currentMode = 'select' // String indicating the current editor mode + this.currentResizeMode = 'none' // String with the current direction in which an element is being resized + this.justSelected = null // The DOM element that was just selected + this.rubberBox = null // DOM element for selection rectangle drawn by the user + this.curBBoxes = [] // Array of current BBoxes, used in getIntersectionList(). + this.lastClickPoint = null // Canvas point for the most recent right click + this.events = {} // Object to contain editor event names and callback functions + this.rootSctm = null // Root Current Transformation Matrix in user units + this.drawnPath = null this.freehand = { // Mouse events minx: null, miny: null, maxx: null, maxy: null - }; - this.dAttr = null; - this.startX = null; - this.startY = null; - this.rStartX = null; - this.rStartY = null; - this.initBbox = {}; - this.sumDistance = 0; - this.controllPoint2 = { x: 0, y: 0 }; - this.controllPoint1 = { x: 0, y: 0 }; - this.start = { x: 0, y: 0 }; - this.end = { x: 0, y: 0 }; - this.bSpline = { x: 0, y: 0 }; - this.nextPos = { x: 0, y: 0 }; - this.idprefix = 'svg_'; // Prefix string for element IDs + } + this.dAttr = null + this.startX = null + this.startY = null + this.rStartX = null + this.rStartY = null + this.initBbox = {} + this.sumDistance = 0 + this.controllPoint2 = { x: 0, y: 0 } + this.controllPoint1 = { x: 0, y: 0 } + this.start = { x: 0, y: 0 } + this.end = { x: 0, y: 0 } + this.bSpline = { x: 0, y: 0 } + this.nextPos = { x: 0, y: 0 } + this.idprefix = 'svg_' // Prefix string for element IDs this.curConfig = { // Default configuration options show_outside_canvas: true, selectNew: true, - dimensions: [ 640, 480 ] - }; + dimensions: [640, 480] + } // Update config with new one if given if (config) { - this.curConfig = SvgCanvas.mergeDeep(this.curConfig, config); + this.curConfig = SvgCanvas.mergeDeep(this.curConfig, config) } - this.lastGoodImgUrl = `${this.curConfig.imgPath}/logo.svg`; // String with image URL of last loadable image - const { dimensions } = this.curConfig; // Array with width/height of canvas + this.lastGoodImgUrl = `${this.curConfig.imgPath}/logo.svg` // String with image URL of last loadable image + const { dimensions } = this.curConfig // Array with width/height of canvas // "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. - this.svgdoc = window.document; - this.container = container; + this.svgdoc = window.document + this.container = container // This is a container for the document being edited, not the document itself. - this.svgroot = svgRootElement(this.svgdoc, dimensions); - container.append(this.svgroot); + this.svgroot = svgRootElement(this.svgdoc, dimensions) + container.append(this.svgroot) // The actual element that represents the final output SVG element. - this.svgContent = this.svgdoc.createElementNS(NS.SVG, 'svg'); - clearInit(this); - this.clearSvgContentElement(); - //Current `draw.Drawing` object. - this.current_drawing_ = new draw.Drawing(this.svgContent, this.idprefix); + this.svgContent = this.svgdoc.createElementNS(NS.SVG, 'svg') + clearInit(this) + this.clearSvgContentElement() + // Current `draw.Drawing` object. + this.current_drawing_ = new draw.Drawing(this.svgContent, this.idprefix) // Float displaying the current zoom level (1 = 100%, .5 = 50%, etc.). - this.zoom = 1; + this.zoom = 1 // pointer to current group (for in-group editing) - this.currentGroup = null; + this.currentGroup = null // Object containing data for the currently selected styles const allProperties = { @@ -195,78 +194,77 @@ class SvgCanvas { stroke_linecap: 'butt', opacity: this.curConfig.initOpacity } - }; - allProperties.text = SvgCanvas.mergeDeep({}, allProperties.shape); + } + allProperties.text = SvgCanvas.mergeDeep({}, allProperties.shape) allProperties.text = SvgCanvas.mergeDeep(allProperties.text, { fill: '#000000', stroke_width: this.curConfig.text && this.curConfig.text.stroke_width, font_size: this.curConfig.text && this.curConfig.text.font_size, font_family: this.curConfig.text && this.curConfig.text.font_family - }); - this.curText = allProperties.text; // Current text style properties + }) + this.curText = allProperties.text // Current text style properties // Current shape style properties - this.curShape = allProperties.shape; - this.curProperties = this.curShape; // Current general properties + this.curShape = allProperties.shape + this.curProperties = this.curShape // Current general properties // Array with all the currently selected elements // default size of 1 until it needs to grow bigger - this.selectedElements = []; + this.selectedElements = [] - jsonInit(this); - unitsInit(this); - utilsInit(this); - coordsInit(this); - recalculateInit(this); - selectInit(this); - undoInit(this); - selectionInit(this); + jsonInit(this) + unitsInit(this) + utilsInit(this) + coordsInit(this) + recalculateInit(this) + selectInit(this) + undoInit(this) + selectionInit(this) - this.nsMap = getReverseNS(); - this.selectorManager = getSelectorManager(); + this.nsMap = getReverseNS() + this.selectorManager = getSelectorManager() - this.pathActions = pathActions; - pathModule.init(this); + this.pathActions = pathActions + pathModule.init(this) // Interface strings, usually for title elements - this.uiStrings = {}; + this.uiStrings = {} // Animation element to change the opacity of any newly created element - this.opacAni = document.createElementNS(NS.SVG, 'animate'); - this.opacAni.setAttribute('attributeName', 'opacity'); - this.opacAni.setAttribute('begin', 'indefinite'); - this.opacAni.setAttribute('dur', 1); - this.opacAni.setAttribute('fill', 'freeze'); - this.svgroot.appendChild(this.opacAni); + this.opacAni = document.createElementNS(NS.SVG, 'animate') + this.opacAni.setAttribute('attributeName', 'opacity') + this.opacAni.setAttribute('begin', 'indefinite') + this.opacAni.setAttribute('dur', 1) + this.opacAni.setAttribute('fill', 'freeze') + this.svgroot.appendChild(this.opacAni) - eventInit(this); - textActionsInit(this); - svgInit(this); - draw.init(this); - elemGetSet.init(this); + eventInit(this) + textActionsInit(this) + svgInit(this) + draw.init(this) + elemGetSet.init(this) // prevent links from being followed in the canvas const handleLinkInCanvas = function (e) { - e.preventDefault(); - return false; - }; - container.addEventListener('mousedown', mouseDownEvent); - container.addEventListener('mousemove', mouseMoveEvent); - container.addEventListener('click', handleLinkInCanvas); - container.addEventListener('dblclick', dblClickEvent); - container.addEventListener('mouseup', mouseUpEvent); - container.addEventListener('mouseleave', mouseOutEvent); - container.addEventListener('mousewheel', DOMMouseScrollEvent); - container.addEventListener('DOMMouseScroll', DOMMouseScrollEvent); + e.preventDefault() + return false + } + container.addEventListener('mousedown', mouseDownEvent) + container.addEventListener('mousemove', mouseMoveEvent) + container.addEventListener('click', handleLinkInCanvas) + container.addEventListener('dblclick', dblClickEvent) + container.addEventListener('mouseup', mouseUpEvent) + container.addEventListener('mouseleave', mouseOutEvent) + container.addEventListener('mousewheel', DOMMouseScrollEvent) + container.addEventListener('DOMMouseScroll', DOMMouseScrollEvent) // Alias function - this.linkControlPoints = pathActions.linkControlPoints; - this.curCommand = null; - this.filter = null; - this.filterHidden = false; - - blurInit(this); - selectedElemInit(this); + this.linkControlPoints = pathActions.linkControlPoints + this.curCommand = null + this.filter = null + this.filterHidden = false + blurInit(this) + selectedElemInit(this) /** * Transfers sessionStorage from one tab to another. @@ -274,66 +272,69 @@ class SvgCanvas { * @returns {void} */ const storageChange = (ev) => { - if (!ev.newValue) return; // This is a call from removeItem. + 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'); - this.flashStorage(); + localStorage.removeItem(CLIPBOARD_ID + '_startup') + this.flashStorage() } else if (ev.key === CLIPBOARD_ID) { // Another tab sent data. - sessionStorage.setItem(CLIPBOARD_ID, ev.newValue); + sessionStorage.setItem(CLIPBOARD_ID, ev.newValue) } - }; + } // Listen for changes to localStorage. - window.addEventListener('storage', storageChange, false); + window.addEventListener('storage', storageChange, false) // Ask other tabs for sessionStorage (this is ONLY to trigger event). - localStorage.setItem(CLIPBOARD_ID + '_startup', Math.random()); + localStorage.setItem(CLIPBOARD_ID + '_startup', Math.random()) - pasteInit(this); + pasteInit(this) - this.contentW = this.getResolution().w; - this.contentH = this.getResolution().h; - this.clear(); + this.contentW = this.getResolution().w + this.contentH = this.getResolution().h + this.clear() } // End constructor - getSvgOption() { return this.saveOptions; } - setSvgOption(key, value) { this.saveOptions[key] = value; } - getSelectedElements() { return this.selectedElements; } - setSelectedElements(key, value) { this.selectedElements[key] = value; } - setEmptySelectedElements() { this.selectedElements = []; } - getSvgRoot() { return this.svgroot; } - getDOMDocument() { return this.svgdoc; } - getDOMContainer() { return this.container; } - getCurConfig() { return this.curConfig; } - setIdPrefix(p) { this.idprefix = p; } - getCurrentDrawing() { return this.current_drawing_;} - getCurShape() { return this.curShape; } - getCurrentGroup() { return this.currentGroup; } - getBaseUnit() { return this.curConfig.baseUnit; } - getHeight() { return this.svgContent.getAttribute('height') / this.zoom; } - getWidth() { return this.svgContent.getAttribute('width') / this.zoom; } - getRoundDigits() { return this.saveOptions.round_digits; } - getSnappingStep() { return this.curConfig.snappingStep; } - getGridSnapping() { return this.curConfig.gridSnapping; } - getStartTransform() { return this.startTransform; } - setStartTransform(transform) { this.startTransform = transform; } - getZoom () { return this.zoom; } - round(val) { return Number.parseInt(val * this.zoom) / this.zoom; } - createSVGElement(jsonMap) { return this.addSVGElemensFromJson(jsonMap); } - getContainer() { return this.container; } - setStarted(s) { this.started = s; } - getRubberBox() { return this.rubberBox; } - setRubberBox(rb) { - this.rubberBox = rb; - return this.rubberBox; + + getSvgOption () { return this.saveOptions } + setSvgOption (key, value) { this.saveOptions[key] = value } + getSelectedElements () { return this.selectedElements } + setSelectedElements (key, value) { this.selectedElements[key] = value } + setEmptySelectedElements () { this.selectedElements = [] } + getSvgRoot () { return this.svgroot } + getDOMDocument () { return this.svgdoc } + getDOMContainer () { return this.container } + getCurConfig () { return this.curConfig } + setIdPrefix (p) { this.idprefix = p } + getCurrentDrawing () { return this.current_drawing_ } + getCurShape () { return this.curShape } + getCurrentGroup () { return this.currentGroup } + getBaseUnit () { return this.curConfig.baseUnit } + getHeight () { return this.svgContent.getAttribute('height') / this.zoom } + getWidth () { return this.svgContent.getAttribute('width') / this.zoom } + getRoundDigits () { return this.saveOptions.round_digits } + getSnappingStep () { return this.curConfig.snappingStep } + getGridSnapping () { return this.curConfig.gridSnapping } + getStartTransform () { return this.startTransform } + setStartTransform (transform) { this.startTransform = transform } + getZoom () { return this.zoom } + round (val) { return Number.parseInt(val * this.zoom) / this.zoom } + createSVGElement (jsonMap) { return this.addSVGElemensFromJson(jsonMap) } + getContainer () { return this.container } + setStarted (s) { this.started = s } + getRubberBox () { return this.rubberBox } + setRubberBox (rb) { + this.rubberBox = rb + return this.rubberBox } - addPtsToSelection({ closedSubpath, grips }) { + + addPtsToSelection ({ closedSubpath, grips }) { // TODO: Correct this: - this.pathActions.canDeleteNodes = true; - this.pathActions.closed_subpath = closedSubpath; - this.call('pointsAdded', { closedSubpath, grips }); - this.call('selected', grips); + this.pathActions.canDeleteNodes = true + this.pathActions.closed_subpath = closedSubpath + this.call('pointsAdded', { closedSubpath, grips }) + this.call('selected', grips) } + /** * @param {PlainObject} changes * @param {ChangeElementCommand} changes.cmd @@ -341,153 +342,159 @@ class SvgCanvas { * @fires module:svgcanvas.SvgCanvas#event:changed * @returns {void} */ - endChanges({ cmd, elem }) { - this.addCommandToHistory(cmd); - this.call('changed', [ elem ]); + endChanges ({ cmd, elem }) { + this.addCommandToHistory(cmd) + this.call('changed', [elem]) } - getCurrentMode() { return this.currentMode; } - setCurrentMode(cm) { - this.currentMode = cm; - return this.currentMode; + + getCurrentMode () { return this.currentMode } + setCurrentMode (cm) { + this.currentMode = cm + return this.currentMode } - getDrawnPath() { return this.drawnPath; } - setDrawnPath(dp) { - this.drawnPath = dp; - return this.drawnPath; + + getDrawnPath () { return this.drawnPath } + setDrawnPath (dp) { + this.drawnPath = dp + return this.drawnPath } - setCurrentGroup(cg) { this.currentGroup = cg; } - changeSvgContent() { this.call('changed', [ this.svgContent ]); } - getStarted() { return this.started; } - getCanvas() { return this; } - getrootSctm() { return this.rootSctm; } - getStartX() { return this.startX; } - setStartX(value) { this.startX = value; } - getStartY() { return this.startY; } - setStartY(value) { this.startY = value; } - getRStartX() { return this.rStartX; } - getRStartY() { return this.rStartY; } - getInitBbox() { return this.initBbox; } - getCurrentResizeMode() { return this.currentResizeMode; } - getJustSelected() { return this.justSelected; } - getOpacAni() { return this.opacAni; } - getParameter() { return this.parameter; } - getNextParameter() { return this.nextParameter; } - getStepCount() { return STEP_COUNT; } - getThreSholdDist() { return THRESHOLD_DIST; } - getSumDistance() { return this.sumDistance; } - getStart(key) { return this.start[key]; } - getEnd(key) { return this.end[key]; } - getbSpline(key) { return this.bSpline[key]; } - getNextPos(key) { return this.nextPos[key]; } - getControllPoint1(key) { return this.controllPoint1[key]; } - getControllPoint2(key) { return this.controllPoint2[key]; } - getFreehand(key) { return this.freehand[key]; } - getDrawing() { return this.getCurrentDrawing(); } - getDAttr() { return this.dAttr; } - getLastGoodImgUrl() { return this.lastGoodImgUrl; } - getCurText(key) { return this.curText[key]; } - setDAttr(value) { this.dAttr = value; } - setEnd(key, value) { this.end[key] = value; } - setControllPoint1(key, value) { this.controllPoint1[key] = value; } - setControllPoint2(key, value) { this.controllPoint2[key] = value; } - setJustSelected(value) { this.justSelected = value; } - setParameter(value) { this.parameter = value; } - setStart(value) { this.start = value; } - setRStartX(value) { this.rStartX = value; } - setRStartY(value) { this.rStartY = value; } - setSumDistance(value) { this.sumDistance = value; } - setbSpline(value) { this.bSpline = value; } - setNextPos(value) { this.nextPos = value; } - setNextParameter(value) { this.nextParameter = value; } - setCurProperties(key, value) { this.curProperties[key] = value; } - setCurText(key, value) { this.curText[key] = value; } - setFreehand(key, value) { this.freehand[key] = value; } - setCurBBoxes(value) { this.curBBoxes = value; } - getCurBBoxes() { return this.curBBoxes; } - setInitBbox(value) { this.initBbox = value; } - setRootSctm(value) { this.rootSctm = value; } - setCurrentResizeMode(value) { this.currentResizeMode = value; } - getLastClickPoint(key) { return this.lastClickPoint[key]; } - setLastClickPoint(value) { this.lastClickPoint = value; } - getId() { return this.getCurrentDrawing().getId(); } - getUIStrings() { return this.uiStrings; } - getNsMap() { return this.nsMap; } - getSvgOptionApply() { return this.saveOptions.apply; } - getSvgOptionImages() { return this.saveOptions.images; } - getEncodableImages(key) { return this.encodableImages[key]; } - setEncodableImages(key, value) { this.encodableImages[key] = value; } - getVisElems() { return visElems; } - getIdPrefix() { return this.idprefix; } - getDataStorage() { return dataStorage; } - setZoom(value) { this.zoom = value; } - getImportIds(key) { return this.importIds[key]; } - setImportIds(key, value) { this.importIds[key] = value; } - setRemovedElements(key, value) { this.removedElements[key] = value; } - setSvgContent(value) { this.svgContent = value; } - getrefAttrs() { return refAttrs; } - getcanvg() { return canvg; } - setCanvas(key, value) { this[key] = value; } - getCurProperties(key) { return this.curProperties[key]; } - setCurShape(key, value) { this.curShape[key] = value; } - gettingSelectorManager() { return this.selectorManager; } - getContentW() { return this.contentW; } - getContentH() { return this.contentH; } - getClipboardID() { return CLIPBOARD_ID; } - getSvgContent() { return this.svgContent; } - getExtensions() { return this.extensions; } - getSelector() { return Selector; } - getMode() { return this.currentMode; } // The current editor mode string - getNextId() { return this.getCurrentDrawing().getNextId(); } - getCurCommand() { return this.curCommand; } - setCurCommand(value) { this.curCommand = value; } - getFilter() { return this.filter; } - setFilter(value) { this.filter = value; } - getFilterHidden() { return this.filterHidden; } - setFilterHidden(value) { this.filterHidden = value; } + + setCurrentGroup (cg) { this.currentGroup = cg } + changeSvgContent () { this.call('changed', [this.svgContent]) } + getStarted () { return this.started } + getCanvas () { return this } + getrootSctm () { return this.rootSctm } + getStartX () { return this.startX } + setStartX (value) { this.startX = value } + getStartY () { return this.startY } + setStartY (value) { this.startY = value } + getRStartX () { return this.rStartX } + getRStartY () { return this.rStartY } + getInitBbox () { return this.initBbox } + getCurrentResizeMode () { return this.currentResizeMode } + getJustSelected () { return this.justSelected } + getOpacAni () { return this.opacAni } + getParameter () { return this.parameter } + getNextParameter () { return this.nextParameter } + getStepCount () { return STEP_COUNT } + getThreSholdDist () { return THRESHOLD_DIST } + getSumDistance () { return this.sumDistance } + getStart (key) { return this.start[key] } + getEnd (key) { return this.end[key] } + getbSpline (key) { return this.bSpline[key] } + getNextPos (key) { return this.nextPos[key] } + getControllPoint1 (key) { return this.controllPoint1[key] } + getControllPoint2 (key) { return this.controllPoint2[key] } + getFreehand (key) { return this.freehand[key] } + getDrawing () { return this.getCurrentDrawing() } + getDAttr () { return this.dAttr } + getLastGoodImgUrl () { return this.lastGoodImgUrl } + getCurText (key) { return this.curText[key] } + setDAttr (value) { this.dAttr = value } + setEnd (key, value) { this.end[key] = value } + setControllPoint1 (key, value) { this.controllPoint1[key] = value } + setControllPoint2 (key, value) { this.controllPoint2[key] = value } + setJustSelected (value) { this.justSelected = value } + setParameter (value) { this.parameter = value } + setStart (value) { this.start = value } + setRStartX (value) { this.rStartX = value } + setRStartY (value) { this.rStartY = value } + setSumDistance (value) { this.sumDistance = value } + setbSpline (value) { this.bSpline = value } + setNextPos (value) { this.nextPos = value } + setNextParameter (value) { this.nextParameter = value } + setCurProperties (key, value) { this.curProperties[key] = value } + setCurText (key, value) { this.curText[key] = value } + setFreehand (key, value) { this.freehand[key] = value } + setCurBBoxes (value) { this.curBBoxes = value } + getCurBBoxes () { return this.curBBoxes } + setInitBbox (value) { this.initBbox = value } + setRootSctm (value) { this.rootSctm = value } + setCurrentResizeMode (value) { this.currentResizeMode = value } + getLastClickPoint (key) { return this.lastClickPoint[key] } + setLastClickPoint (value) { this.lastClickPoint = value } + getId () { return this.getCurrentDrawing().getId() } + getUIStrings () { return this.uiStrings } + getNsMap () { return this.nsMap } + getSvgOptionApply () { return this.saveOptions.apply } + getSvgOptionImages () { return this.saveOptions.images } + getEncodableImages (key) { return this.encodableImages[key] } + setEncodableImages (key, value) { this.encodableImages[key] = value } + getVisElems () { return visElems } + getIdPrefix () { return this.idprefix } + getDataStorage () { return dataStorage } + setZoom (value) { this.zoom = value } + getImportIds (key) { return this.importIds[key] } + setImportIds (key, value) { this.importIds[key] = value } + setRemovedElements (key, value) { this.removedElements[key] = value } + setSvgContent (value) { this.svgContent = value } + getrefAttrs () { return refAttrs } + getcanvg () { return canvg } + setCanvas (key, value) { this[key] = value } + getCurProperties (key) { return this.curProperties[key] } + setCurShape (key, value) { this.curShape[key] = value } + gettingSelectorManager () { return this.selectorManager } + getContentW () { return this.contentW } + getContentH () { return this.contentH } + getClipboardID () { return CLIPBOARD_ID } + getSvgContent () { return this.svgContent } + getExtensions () { return this.extensions } + getSelector () { return Selector } + getMode () { return this.currentMode } // The current editor mode string + getNextId () { return this.getCurrentDrawing().getNextId() } + getCurCommand () { return this.curCommand } + setCurCommand (value) { this.curCommand = value } + getFilter () { return this.filter } + setFilter (value) { this.filter = value } + getFilterHidden () { return this.filterHidden } + setFilterHidden (value) { this.filterHidden = value } /** * 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} */ - setMode(name) { - this.pathActions.clear(true); - this.textActions.clear(); - this.curProperties = (this.selectedElements[0] && this.selectedElements[0].nodeName === 'text') ? this.curText : this.curShape; - this.currentMode = name; + setMode (name) { + this.pathActions.clear(true) + this.textActions.clear() + this.curProperties = (this.selectedElements[0] && this.selectedElements[0].nodeName === 'text') ? this.curText : this.curShape + this.currentMode = name } + /** * Clears the current document. This is not an undoable action. * @function module:svgcanvas.SvgCanvas#clear * @fires module:svgcanvas.SvgCanvas#event:cleared * @returns {void} */ - clear() { - this.pathActions.clear(); - this.clearSelection(); + clear () { + this.pathActions.clear() + this.clearSelection() // clear the svgcontent node - this.clearSvgContentElement(); + this.clearSvgContentElement() // create new document - this.current_drawing_ = new draw.Drawing(this.svgContent); + this.current_drawing_ = new draw.Drawing(this.svgContent) // create empty first layer - this.createLayer('Layer 1'); + this.createLayer('Layer 1') // clear the undo stack - this.undoMgr.resetUndoStack(); + this.undoMgr.resetUndoStack() // reset the selector manager - this.selectorManager.initGroup(); + this.selectorManager.initGroup() // reset the rubber band box - this.rubberBox = this.selectorManager.getRubberBandBox(); - this.call('cleared'); + this.rubberBox = this.selectorManager.getRubberBandBox() + this.call('cleared') } + runExtension (name, action, vars) { - return this.runExtensions(action, vars, false, (n) => n === name); + return this.runExtensions(action, vars, false, (n) => n === name) } - async addExtension (name, extInitFunc, { importLocale }) { + + async addExtension (name, extInitFunc, { importLocale }) { if (typeof extInitFunc !== 'function') { - throw new TypeError('Function argument expected for `svgcanvas.addExtension`'); + throw new TypeError('Function argument expected for `svgcanvas.addExtension`') } if (name in this.extensions) { - throw new Error('Cannot add extension "' + name + '", an extension by that name already exists.'); + throw new Error('Cannot add extension "' + name + '", an extension by that name already exists.') } const argObj = { importLocale, @@ -495,45 +502,48 @@ class SvgCanvas { svgContent: this.svgContent, nonce: this.getCurrentDrawing().getNonce(), selectorManager: this.selectorManager - }; - const extObj = await extInitFunc(argObj); - if (extObj) { - extObj.name = name; } - this.extensions[name] = extObj; - return this.call('extension_added', extObj); + const extObj = await extInitFunc(argObj) + if (extObj) { + extObj.name = name + } + this.extensions[name] = extObj + return this.call('extension_added', extObj) } - addCommandToHistory(cmd) { this.undoMgr.addCommandToHistory(cmd); } - restoreRefElements(elem) { + + addCommandToHistory (cmd) { this.undoMgr.addCommandToHistory(cmd) } + restoreRefElements (elem) { // Look for missing reference elements, restore any found - const attrs = {}; + const attrs = {} refAttrs.forEach(function (item, _) { - attrs[item] = elem.getAttribute(item); - }); + attrs[item] = elem.getAttribute(item) + }) Object.values(attrs).forEach((val) => { if (val && val.startsWith('url(')) { - const id = getUrlFromAttr(val).substr(1); - const ref = getElem(id); + const id = getUrlFromAttr(val).substr(1) + const ref = getElem(id) if (!ref) { - findDefs().append(this.removedElements[id]); - delete this.removedElements[id]; + findDefs().append(this.removedElements[id]) + delete this.removedElements[id] } } - }); - const childs = elem.getElementsByTagName('*'); + }) + const childs = elem.getElementsByTagName('*') if (childs.length) { for (let i = 0, l = childs.length; i < l; i++) { - this.restoreRefElements(childs[i]); + this.restoreRefElements(childs[i]) } } } - call(ev, arg) { + + call (ev, arg) { if (this.events[ev]) { - return this.events[ev](window, arg); + return this.events[ev](window, arg) } - return undefined; + return undefined } + /** * Attaches a callback function to an event. * @function module:svgcanvas.SvgCanvas#bind @@ -542,21 +552,23 @@ class SvgCanvas { * @returns {module:svgcanvas.EventHandler} The previous event */ bind (ev, f) { - const old = this.events[ev]; - this.events[ev] = f; - return old; + const old = this.events[ev] + this.events[ev] = f + return old } + /** * Flash the clipboard data momentarily on localStorage so all tabs can see. * @returns {void} */ - flashStorage() { - const data = sessionStorage.getItem(CLIPBOARD_ID); - localStorage.setItem(CLIPBOARD_ID, data); + flashStorage () { + const data = sessionStorage.getItem(CLIPBOARD_ID) + localStorage.setItem(CLIPBOARD_ID, data) setTimeout(function () { - localStorage.removeItem(CLIPBOARD_ID); - }, 1); + localStorage.removeItem(CLIPBOARD_ID) + }, 1) } + /** * Selects only the given elements, shortcut for `clearSelection(); addToSelection()`. * @function module:svgcanvas.SvgCanvas#selectOnly @@ -564,129 +576,136 @@ class SvgCanvas { * @param {boolean} showGrips - Indicates whether the resize grips should be shown * @returns {void} */ - selectOnly(elems, showGrips) { - this.clearSelection(true); - this.addToSelection(elems, showGrips); + selectOnly (elems, showGrips) { + this.clearSelection(true) + this.addToSelection(elems, showGrips) } + /** * Removes elements from the selection. * @function module:svgcanvas.SvgCanvas#removeFromSelection * @param {Element[]} elemsToRemove - An array of elements to remove from selection * @returns {void} */ - removeFromSelection(elemsToRemove) { - if (isNullish(this.selectedElements[0])) { return; } - if (!elemsToRemove.length) { return; } + removeFromSelection (elemsToRemove) { + if (isNullish(this.selectedElements[0])) { return } + if (!elemsToRemove.length) { return } // find every element and remove it from our array copy - const newSelectedItems = []; - const len = this.selectedElements.length; + const newSelectedItems = [] + const len = this.selectedElements.length for (let i = 0; i < len; ++i) { - const elem = this.selectedElements[i]; + const elem = this.selectedElements[i] if (elem) { // keep the item if (!elemsToRemove.includes(elem)) { - newSelectedItems.push(elem); + newSelectedItems.push(elem) } else { // remove the item and its selector - this.selectorManager.releaseSelector(elem); + this.selectorManager.releaseSelector(elem) } } } // the copy becomes the master now - this.selectedElements = newSelectedItems; + this.selectedElements = newSelectedItems } + /** * Clears the selection, then adds all elements in the current layer to the selection. * @function module:svgcanvas.SvgCanvas#selectAllInCurrentLayer * @returns {void} */ - selectAllInCurrentLayer() { - const currentLayer = this.getCurrentDrawing().getCurrentLayer(); + selectAllInCurrentLayer () { + const currentLayer = this.getCurrentDrawing().getCurrentLayer() if (currentLayer) { - this.currentMode = 'select'; + this.currentMode = 'select' if (this.currentGroup) { - this.selectOnly(this.currentGroup.children); + this.selectOnly(this.currentGroup.children) } else { - this.selectOnly(currentLayer.children); + this.selectOnly(currentLayer.children) } } } - getOpacity() { - return this.curShape.opacity; + + getOpacity () { + return this.curShape.opacity } + /** * @function module:svgcanvas.SvgCanvas#getSnapToGrid * @returns {boolean} The current snap to grid setting */ - getSnapToGrid() { return this.curConfig.gridSnapping; } + getSnapToGrid () { return this.curConfig.gridSnapping } /** * @function module:svgcanvas.SvgCanvas#getVersion * @returns {string} A string which describes the revision number of SvgCanvas. */ - getVersion() { return 'svgcanvas.js ($Rev$)'; } + getVersion () { 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} */ - setUiStrings(strs) { - Object.assign(this.uiStrings, strs.notification); - pathModule.setUiStrings(strs); + setUiStrings (strs) { + Object.assign(this.uiStrings, strs.notification) + pathModule.setUiStrings(strs) } + /** * Update configuration options with given values. * @function module:svgcanvas.SvgCanvas#setConfig * @param {module:SVGEditor.Config} opts - Object with options * @returns {void} */ - setConfig(opts) { Object.assign(this.curConfig, opts); } + setConfig (opts) { Object.assign(this.curConfig, opts) } /** * @function module:svgcanvas.SvgCanvas#getDocumentTitle * @returns {string|void} The current document title or an empty string if not found */ - getDocumentTitle() { return this.getTitle(this.svgContent); } - getOffset() { - return { x: Number(this.svgContent.getAttribute('x')), y: Number(this.svgContent.getAttribute('y')) }; + getDocumentTitle () { return this.getTitle(this.svgContent) } + getOffset () { + return { x: Number(this.svgContent.getAttribute('x')), y: Number(this.svgContent.getAttribute('y')) } } - getColor(type) { return this.curProperties[type]; } - setStrokePaint(paint) { this.setPaint('stroke', paint); } + + getColor (type) { return this.curProperties[type] } + setStrokePaint (paint) { this.setPaint('stroke', paint) } /** * @function module:svgcanvas.SvgCanvas#setFillPaint * @param {module:jGraduate~Paint} paint * @returns {void} */ - setFillPaint(paint) { this.setPaint('fill', paint); } + setFillPaint (paint) { this.setPaint('fill', paint) } /** * @function module:svgcanvas.SvgCanvas#getStrokeWidth * @returns {Float|string} The current stroke-width value */ - getStrokeWidth() { return this.curProperties.stroke_width; } + getStrokeWidth () { return this.curProperties.stroke_width } /** * @function module:svgcanvas.SvgCanvas#getStyle * @returns {module:svgcanvas.StyleOptions} current style options */ - getStyle() { return this.curShape; } + getStyle () { return this.curShape } /** * Sets the given opacity on the current selected elements. * @function module:svgcanvas.SvgCanvas#setOpacity * @param {string} val * @returns {void} */ - setOpacity(val) { - this.curShape.opacity = val; - this.changeSelectedAttribute('opacity', val); + setOpacity (val) { + this.curShape.opacity = val + this.changeSelectedAttribute('opacity', val) } + /** * @function module:svgcanvas.SvgCanvas#getFillOpacity * @returns {Float} the current fill opacity */ - getFillOpacity() { return this.curShape.fill_opacity; } + getFillOpacity () { return this.curShape.fill_opacity } /** * @function module:svgcanvas.SvgCanvas#getStrokeOpacity * @returns {string} the current stroke opacity */ - getStrokeOpacity() { return this.curShape.stroke_opacity; } + getStrokeOpacity () { return this.curShape.stroke_opacity } /** * Sets the current fill/stroke opacity. * @function module:svgcanvas.SvgCanvas#setPaintOpacity @@ -695,64 +714,68 @@ class SvgCanvas { * @param {boolean} preventUndo - Indicates whether or not this should be an undoable action * @returns {void} */ - setPaintOpacity(type, val, preventUndo) { - this.curShape[type + '_opacity'] = val; + setPaintOpacity (type, val, preventUndo) { + this.curShape[type + '_opacity'] = val if (!preventUndo) { - this.changeSelectedAttribute(type + '-opacity', val); + this.changeSelectedAttribute(type + '-opacity', val) } else { - this.changeSelectedAttributeNoUndo(type + '-opacity', val); + this.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 */ - getPaintOpacity(type) { - return type === 'fill' ? this.getFillOpacity() : this.getStrokeOpacity(); + getPaintOpacity (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 */ - getBlur(elem) { - let val = 0; + getBlur (elem) { + let val = 0 if (elem) { - const filterUrl = elem.getAttribute('filter'); + const filterUrl = elem.getAttribute('filter') if (filterUrl) { - const blur = getElem(elem.id + '_blur'); + const blur = getElem(elem.id + '_blur') if (blur) { - val = blur.firstChild.getAttribute('stdDeviation'); + val = blur.firstChild.getAttribute('stdDeviation') } else { - const filterElem = getRefElem(filterUrl); - const blurElem = getFeGaussianBlur(filterElem); + const filterElem = getRefElem(filterUrl) + const blurElem = getFeGaussianBlur(filterElem) if (blurElem !== null) { - val = blurElem.getAttribute('stdDeviation'); + val = blurElem.getAttribute('stdDeviation') } } } } - return val; + return val } + /** * Sets a given URL to be a "last good image" URL. * @function module:svgcanvas.SvgCanvas#setGoodImage * @param {string} val * @returns {void} */ - setGoodImage(val) { this.lastGoodImgUrl = val; } + setGoodImage (val) { this.lastGoodImgUrl = val } /** * Returns the current drawing as raw SVG XML text. * @function module:svgcanvas.SvgCanvas#getSvgString * @returns {string} The current drawing as raw SVG XML text. */ getSvgString () { - this.saveOptions.apply = false; - return this.svgCanvasToString(); + this.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. @@ -765,11 +788,12 @@ class SvgCanvas { */ randomizeIds (enableRandomization) { if (arguments.length > 0 && enableRandomization === false) { - draw.randomizeIds(false, this.getCurrentDrawing()); + draw.randomizeIds(false, this.getCurrentDrawing()) } else { - draw.randomizeIds(true, this.getCurrentDrawing()); + draw.randomizeIds(true, this.getCurrentDrawing()) } } + /** * Convert selected element to a path, or get the BBox of an element-as-path. * @function module:svgcanvas.SvgCanvas#convertToPath @@ -779,16 +803,16 @@ class SvgCanvas { * @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. */ - convertToPath(elem, getBBox) { + convertToPath (elem, getBBox) { if (isNullish(elem)) { - const elems = this.selectedElements; + const elems = this.selectedElements elems.forEach((el) => { - if (el) { this.convertToPath(el); } - }); - return undefined; + if (el) { this.convertToPath(el) } + }) + return undefined } if (getBBox) { - return getBBoxOfElementAsPath(elem, this.addSVGElemensFromJson, this.pathActions); + return getBBoxOfElementAsPath(elem, this.addSVGElemensFromJson, this.pathActions) } // TODO: Why is this applying attributes from this.curShape, then inside utilities.convertToPath it's pulling addition attributes from elem? // TODO: If convertToPath is called with one elem, this.curShape and elem are probably the same; but calling with multiple is a bug or cool feature. @@ -803,157 +827,159 @@ class SvgCanvas { 'stroke-opacity': this.curShape.stroke_opacity, opacity: this.curShape.opacity, visibility: 'hidden' - }; + } return convertToPath( elem, attrs, this.addSVGElemensFromJson, this.pathActions, this.clearSelection, this.addToSelection, history, this.addCommandToHistory - ); + ) } + /** * 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} */ - cutSelectedElements() { - this.copySelectedElements(); - this.deleteSelectedElements(); + cutSelectedElements () { + this.copySelectedElements() + this.deleteSelectedElements() } - initializeSvgCanvasMethods() { - this.getJsonFromSvgElements = getJsonFromSvgElements; - this.addSVGElemensFromJson = addSVGElementsFromJson; - this.clearSvgContentElement = clearSvgContentElementInit; - this.textActions = textActionsMethod; - this.getIntersectionList = getIntersectionListMethod; - this.getStrokedBBox = getStrokedBBoxDefaultVisible; - this.getVisibleElements = getVisibleElements; - this.uniquifyElems = uniquifyElemsMethod; - this.setUseData = setUseDataMethod; - this.convertGradients = convertGradientsMethod; - this.setSvgString = setSvgString; - this.importSvgString = importSvgString; - this.runExtensions = runExtensionsMethod; - this.clearSelection = clearSelectionMethod; - this.addToSelection = addToSelectionMethod; - this.stringToHTML = stringToHTML; - this.insertChildAtIndex = insertChildAtIndex; - this.getClosest = getClosest; - this.getParents = getParents; - this.isLayer = draw.Layer.isLayer; - this.matrixMultiply = matrixMultiply; - this.hasMatrixTransform = hasMatrixTransform; - this.transformListToTransform = transformListToTransform; - this.convertToNum = convertToNum; - this.findDefs = findDefs; - this.getUrlFromAttr = getUrlFromAttr; - this.getHref = getHref; - this.setHref = setHref; - this.getBBox = utilsGetBBox; - this.getRotationAngle = getRotationAngle; - this.getElem = getElem; - this.getRefElem = getRefElem; - this.assignAttributes = assignAttributes; - this.cleanupElement = cleanupElement; - this.remapElement = remapElement; - this.recalculateDimensions = recalculateDimensions; - this.sanitizeSvg = sanitizeSvg; - this.groupSvgElem = groupSvgElem; // Wrap an SVG element into a group element, mark the group as 'gsvg'. - this.prepareSvg = prepareSvg; //Runs the SVG Document through the sanitizer and then updates its paths. - this.setRotationAngle = setRotationAngle; // Removes any old rotations if present, prepends a new rotation at the transformed center. - this.recalculateAllSelectedDimensions = recalculateAllSelectedDimensions; // Runs `recalculateDimensions` on selected elements,adding changes to a single batch command. - this.copySelectedElements = copySelectedElements; - this.pasteElements = pasteElementsMethod; // Remembers the current selected elements on the clipboard. - this.groupSelectedElements = groupSelectedElements; // Wraps all the selected elements in a group (`g`) element. - this.pushGroupProperties = pushGroupProperty; // Pushes all appropriate parent group properties down to its children - this.ungroupSelectedElement = ungroupSelectedElement; // Unwraps all the elements in a selected group (`g`) element - this.moveToTopSelectedElement = moveToTopSelectedElem; // Repositions the selected element to the bottom in the DOM to appear on top - this.moveToBottomSelectedElement = moveToBottomSelectedElem; // Repositions the selected element to the top in the DOM to appear under other elements - this.moveUpDownSelected = moveUpDownSelected; // Moves the select element up or down the stack, based on the visibly - this.moveSelectedElements = moveSelectedElements; // Moves selected elements on the X/Y axis. - this.cloneSelectedElements = cloneSelectedElements; // Create deep DOM copies (clones) of all selected elements and move them slightly - this.alignSelectedElements = alignSelectedElements; // Aligns selected elements. - this.updateCanvas = updateCanvas; // Updates the editor canvas width/height/position after a zoom has occurred. - this.cycleElement = cycleElement; // Select the next/previous element within the current layer. - this.getMouseTarget = getMouseTargetMethod; - this.removeUnusedDefElems = removeUnusedDefElemsMethod; //remove DOM elements inside the `<defs>` if they are notreferred to, - this.svgCanvasToString = svgCanvasToString; // Main function to set up the SVG content for output. - this.svgToString = svgToString; // Sub function ran on each SVG element to convert it to a string as desired. - this.embedImage = embedImage; // Converts a given image file to a data URL when possibl - this.rasterExport = rasterExport; // Generates a PNG (or JPG, BMP, WEBP) Data URL based on the current image - this.exportPDF = exportPDF; // Generates a PDF based on the current image, then calls "exportedPDF" - this.identifyLayers = draw.identifyLayers; - this.createLayer = draw.createLayer; - this.cloneLayer = draw.cloneLayer; - this.deleteCurrentLayer = draw.deleteCurrentLayer; - this.setCurrentLayer = draw.setCurrentLayer; - this.renameCurrentLayer = draw.renameCurrentLayer; - this.setCurrentLayerPosition = draw.setCurrentLayerPosition; - this.setLayerVisibility = draw.setLayerVisibility; - this.moveSelectedToLayer = draw.moveSelectedToLayer; - this.mergeLayer = draw.mergeLayer; - this.mergeAllLayers = draw.mergeAllLayers; - this.leaveContext = draw.leaveContext; - this.setContext = draw.setContext; - this.getBold = elemGetSet.getBoldMethod; // Check whether selected element is bold or not. - this.setBold = elemGetSet.setBoldMethod; // Make the selected element bold or normal. - this.getItalic = elemGetSet.getItalicMethod; // Check whether selected element is in italics or not. - this.setItalic = elemGetSet.setItalicMethod; // Make the selected element italic or normal. - this.setTextAnchor = elemGetSet.setTextAnchorMethod; // Set the new text anchor. - this.getFontFamily = elemGetSet.getFontFamilyMethod; // The current font family - this.setFontFamily = elemGetSet.setFontFamilyMethod; // Set the new font family. - this.setFontColor = elemGetSet.setFontColorMethod; // Set the new font color. - this.getFontColor = elemGetSet.getFontColorMethod; // The current font color - this.getFontSize = elemGetSet.getFontSizeMethod; // The current font size - this.setFontSize = elemGetSet.setFontSizeMethod; // Applies the given font size to the selected element. - this.getText = elemGetSet.getTextMethod; // current text (`textContent`) of the selected element - this.setTextContent = elemGetSet.setTextContentMethod; // Updates the text element with the given string. - this.setImageURL = elemGetSet.setImageURLMethod; // Sets the new image URL for the selected image element - this.setLinkURL = elemGetSet.setLinkURLMethod; // Sets the new link URL for the selected anchor element. - this.setRectRadius = elemGetSet.setRectRadiusMethod; // Sets the `rx` and `ry` values to the selected `rect` element - this.makeHyperlink = elemGetSet.makeHyperlinkMethod; // Wraps the selected element(s) in an anchor element or converts group to one. - this.removeHyperlink = elemGetSet.removeHyperlinkMethod; - this.setSegType = elemGetSet.setSegTypeMethod; // Sets the new segment type to the selected segment(s). - this.setStrokeWidth = elemGetSet.setStrokeWidthMethod; // Sets the stroke width for the current selected elements. - this.getResolution = elemGetSet.getResolutionMethod; // The current dimensions and zoom level in an object - this.getTitle = elemGetSet.getTitleMethod; // the current group/SVG's title contents or `undefined` if no element - this.setGroupTitle = elemGetSet.setGroupTitleMethod; // Sets the group/SVG's title content. - this.setStrokeAttr = elemGetSet.setStrokeAttrMethod; // Set the given stroke-related attribute the given value for selected elements. - this.setBackground = elemGetSet.setBackgroundMethod; // Set the background of the editor (NOT the actual document). - this.setDocumentTitle = elemGetSet.setDocumentTitleMethod; // Adds/updates a title element for the document with the given name. - this.getEditorNS = elemGetSet.getEditorNSMethod; // Returns the editor's namespace URL, optionally adding it to the root element. - this.setResolution = elemGetSet.setResolutionMethod; // Changes the document's dimensions to the given size. - this.setBBoxZoom = elemGetSet.setBBoxZoomMethod; // Sets the zoom level on the canvas-side based on the given value. - this.setCurrentZoom = elemGetSet.setZoomMethod; // Sets the zoom to the given level. - this.setColor = elemGetSet.setColorMethod; // Change the current stroke/fill color/gradien - this.setGradient = elemGetSet.setGradientMethod; // Apply the current gradient to selected element's fill or stroke. - this.setPaint = elemGetSet.setPaintMethod; // Set a color/gradient to a fill/stroke. - this.changeSelectedAttributeNoUndo = changeSelectedAttributeNoUndoMethod; // This function makes the changes to the elements. It does not add the change to the history stack. - this.changeSelectedAttribute = changeSelectedAttributeMethod; // Change the given/selected element and add the original value to the history stack. - this.deleteSelectedElements = deleteSelectedElements; // Removes all selected elements from the DOM and adds the change to the history - this.setBlurNoUndo = setBlurNoUndo; // Sets the `stdDeviation` blur value on the selected element without being undoable. - this.setBlurOffsets = setBlurOffsets; // 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. - this.setBlur = setBlur; // Adds/updates the blur filter to the selected element. - this.smoothControlPoints = pathModule.smoothControlPoints; - this.getTypeMap = getTypeMap; - this.history = history; // object with all histor methods - this.NS = NS; - this.$id = $id; - this.$qq = $qq; - this.$qa = $qa; + + initializeSvgCanvasMethods () { + this.getJsonFromSvgElements = getJsonFromSvgElements + this.addSVGElemensFromJson = addSVGElementsFromJson + this.clearSvgContentElement = clearSvgContentElementInit + this.textActions = textActionsMethod + this.getIntersectionList = getIntersectionListMethod + this.getStrokedBBox = getStrokedBBoxDefaultVisible + this.getVisibleElements = getVisibleElements + this.uniquifyElems = uniquifyElemsMethod + this.setUseData = setUseDataMethod + this.convertGradients = convertGradientsMethod + this.setSvgString = setSvgString + this.importSvgString = importSvgString + this.runExtensions = runExtensionsMethod + this.clearSelection = clearSelectionMethod + this.addToSelection = addToSelectionMethod + this.stringToHTML = stringToHTML + this.insertChildAtIndex = insertChildAtIndex + this.getClosest = getClosest + this.getParents = getParents + this.isLayer = draw.Layer.isLayer + this.matrixMultiply = matrixMultiply + this.hasMatrixTransform = hasMatrixTransform + this.transformListToTransform = transformListToTransform + this.convertToNum = convertToNum + this.findDefs = findDefs + this.getUrlFromAttr = getUrlFromAttr + this.getHref = getHref + this.setHref = setHref + this.getBBox = utilsGetBBox + this.getRotationAngle = getRotationAngle + this.getElem = getElem + this.getRefElem = getRefElem + this.assignAttributes = assignAttributes + this.cleanupElement = cleanupElement + this.remapElement = remapElement + this.recalculateDimensions = recalculateDimensions + this.sanitizeSvg = sanitizeSvg + this.groupSvgElem = groupSvgElem // Wrap an SVG element into a group element, mark the group as 'gsvg'. + this.prepareSvg = prepareSvg // Runs the SVG Document through the sanitizer and then updates its paths. + this.setRotationAngle = setRotationAngle // Removes any old rotations if present, prepends a new rotation at the transformed center. + this.recalculateAllSelectedDimensions = recalculateAllSelectedDimensions // Runs `recalculateDimensions` on selected elements,adding changes to a single batch command. + this.copySelectedElements = copySelectedElements + this.pasteElements = pasteElementsMethod // Remembers the current selected elements on the clipboard. + this.groupSelectedElements = groupSelectedElements // Wraps all the selected elements in a group (`g`) element. + this.pushGroupProperties = pushGroupProperty // Pushes all appropriate parent group properties down to its children + this.ungroupSelectedElement = ungroupSelectedElement // Unwraps all the elements in a selected group (`g`) element + this.moveToTopSelectedElement = moveToTopSelectedElem // Repositions the selected element to the bottom in the DOM to appear on top + this.moveToBottomSelectedElement = moveToBottomSelectedElem // Repositions the selected element to the top in the DOM to appear under other elements + this.moveUpDownSelected = moveUpDownSelected // Moves the select element up or down the stack, based on the visibly + this.moveSelectedElements = moveSelectedElements // Moves selected elements on the X/Y axis. + this.cloneSelectedElements = cloneSelectedElements // Create deep DOM copies (clones) of all selected elements and move them slightly + this.alignSelectedElements = alignSelectedElements // Aligns selected elements. + this.updateCanvas = updateCanvas // Updates the editor canvas width/height/position after a zoom has occurred. + this.cycleElement = cycleElement // Select the next/previous element within the current layer. + this.getMouseTarget = getMouseTargetMethod + this.removeUnusedDefElems = removeUnusedDefElemsMethod // remove DOM elements inside the `<defs>` if they are notreferred to, + this.svgCanvasToString = svgCanvasToString // Main function to set up the SVG content for output. + this.svgToString = svgToString // Sub function ran on each SVG element to convert it to a string as desired. + this.embedImage = embedImage // Converts a given image file to a data URL when possibl + this.rasterExport = rasterExport // Generates a PNG (or JPG, BMP, WEBP) Data URL based on the current image + this.exportPDF = exportPDF // Generates a PDF based on the current image, then calls "exportedPDF" + this.identifyLayers = draw.identifyLayers + this.createLayer = draw.createLayer + this.cloneLayer = draw.cloneLayer + this.deleteCurrentLayer = draw.deleteCurrentLayer + this.setCurrentLayer = draw.setCurrentLayer + this.renameCurrentLayer = draw.renameCurrentLayer + this.setCurrentLayerPosition = draw.setCurrentLayerPosition + this.setLayerVisibility = draw.setLayerVisibility + this.moveSelectedToLayer = draw.moveSelectedToLayer + this.mergeLayer = draw.mergeLayer + this.mergeAllLayers = draw.mergeAllLayers + this.leaveContext = draw.leaveContext + this.setContext = draw.setContext + this.getBold = elemGetSet.getBoldMethod // Check whether selected element is bold or not. + this.setBold = elemGetSet.setBoldMethod // Make the selected element bold or normal. + this.getItalic = elemGetSet.getItalicMethod // Check whether selected element is in italics or not. + this.setItalic = elemGetSet.setItalicMethod // Make the selected element italic or normal. + this.setTextAnchor = elemGetSet.setTextAnchorMethod // Set the new text anchor. + this.getFontFamily = elemGetSet.getFontFamilyMethod // The current font family + this.setFontFamily = elemGetSet.setFontFamilyMethod // Set the new font family. + this.setFontColor = elemGetSet.setFontColorMethod // Set the new font color. + this.getFontColor = elemGetSet.getFontColorMethod // The current font color + this.getFontSize = elemGetSet.getFontSizeMethod // The current font size + this.setFontSize = elemGetSet.setFontSizeMethod // Applies the given font size to the selected element. + this.getText = elemGetSet.getTextMethod // current text (`textContent`) of the selected element + this.setTextContent = elemGetSet.setTextContentMethod // Updates the text element with the given string. + this.setImageURL = elemGetSet.setImageURLMethod // Sets the new image URL for the selected image element + this.setLinkURL = elemGetSet.setLinkURLMethod // Sets the new link URL for the selected anchor element. + this.setRectRadius = elemGetSet.setRectRadiusMethod // Sets the `rx` and `ry` values to the selected `rect` element + this.makeHyperlink = elemGetSet.makeHyperlinkMethod // Wraps the selected element(s) in an anchor element or converts group to one. + this.removeHyperlink = elemGetSet.removeHyperlinkMethod + this.setSegType = elemGetSet.setSegTypeMethod // Sets the new segment type to the selected segment(s). + this.setStrokeWidth = elemGetSet.setStrokeWidthMethod // Sets the stroke width for the current selected elements. + this.getResolution = elemGetSet.getResolutionMethod // The current dimensions and zoom level in an object + this.getTitle = elemGetSet.getTitleMethod // the current group/SVG's title contents or `undefined` if no element + this.setGroupTitle = elemGetSet.setGroupTitleMethod // Sets the group/SVG's title content. + this.setStrokeAttr = elemGetSet.setStrokeAttrMethod // Set the given stroke-related attribute the given value for selected elements. + this.setBackground = elemGetSet.setBackgroundMethod // Set the background of the editor (NOT the actual document). + this.setDocumentTitle = elemGetSet.setDocumentTitleMethod // Adds/updates a title element for the document with the given name. + this.getEditorNS = elemGetSet.getEditorNSMethod // Returns the editor's namespace URL, optionally adding it to the root element. + this.setResolution = elemGetSet.setResolutionMethod // Changes the document's dimensions to the given size. + this.setBBoxZoom = elemGetSet.setBBoxZoomMethod // Sets the zoom level on the canvas-side based on the given value. + this.setCurrentZoom = elemGetSet.setZoomMethod // Sets the zoom to the given level. + this.setColor = elemGetSet.setColorMethod // Change the current stroke/fill color/gradien + this.setGradient = elemGetSet.setGradientMethod // Apply the current gradient to selected element's fill or stroke. + this.setPaint = elemGetSet.setPaintMethod // Set a color/gradient to a fill/stroke. + this.changeSelectedAttributeNoUndo = changeSelectedAttributeNoUndoMethod // This function makes the changes to the elements. It does not add the change to the history stack. + this.changeSelectedAttribute = changeSelectedAttributeMethod // Change the given/selected element and add the original value to the history stack. + this.deleteSelectedElements = deleteSelectedElements // Removes all selected elements from the DOM and adds the change to the history + this.setBlurNoUndo = setBlurNoUndo // Sets the `stdDeviation` blur value on the selected element without being undoable. + this.setBlurOffsets = setBlurOffsets // 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. + this.setBlur = setBlur // Adds/updates the blur filter to the selected element. + this.smoothControlPoints = pathModule.smoothControlPoints + this.getTypeMap = getTypeMap + this.history = history // object with all histor methods + this.NS = NS + this.$id = $id + this.$qq = $qq + this.$qa = $qa } } // End class // attach utilities function to the class that are used by SvgEdit so // we can avoid using the whole utilities.js file in svgEdit.js -SvgCanvas.$id = $id; -SvgCanvas.$qq = $qq; -SvgCanvas.$qa = $qa; -SvgCanvas.isNullish = isNullish; -SvgCanvas.encode64 = encode64; -SvgCanvas.decode64 = decode64; -SvgCanvas.mergeDeep = mergeDeep; -SvgCanvas.getClosest = getClosest; -SvgCanvas.getParents = getParents; -SvgCanvas.blankPageObjectURL = blankPageObjectURL; +SvgCanvas.$id = $id +SvgCanvas.$qq = $qq +SvgCanvas.$qa = $qa +SvgCanvas.isNullish = isNullish +SvgCanvas.encode64 = encode64 +SvgCanvas.decode64 = decode64 +SvgCanvas.mergeDeep = mergeDeep +SvgCanvas.getClosest = getClosest +SvgCanvas.getParents = getParents +SvgCanvas.blankPageObjectURL = blankPageObjectURL -export default SvgCanvas; +export default SvgCanvas diff --git a/src/svgcanvas/svgroot.js b/src/svgcanvas/svgroot.js index 294a1af7..6481a3b5 100644 --- a/src/svgcanvas/svgroot.js +++ b/src/svgcanvas/svgroot.js @@ -5,8 +5,8 @@ * * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller */ -import { NS } from './namespaces.js'; -import { text2xml } from './utilities.js'; +import { NS } from './namespaces.js' +import { text2xml } from './utilities.js' /** * @function module:svgcanvas.svgRootElement svgRootElement the svg node and its children. @@ -32,5 +32,5 @@ export const svgRootElement = function (svgdoc, dimensions) { </svg>` ).documentElement, true - ); -}; + ) +} diff --git a/src/svgcanvas/text-actions.js b/src/svgcanvas/text-actions.js index 4849cb2f..9a201fbc 100644 --- a/src/svgcanvas/text-actions.js +++ b/src/svgcanvas/text-actions.js @@ -5,19 +5,18 @@ * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller */ - -import { NS } from './namespaces.js'; +import { NS } from './namespaces.js' import { transformPoint, getMatrix -} from './math.js'; +} from './math.js' import { assignAttributes, getElem, getBBox as utilsGetBBox -} from './utilities.js'; +} from './utilities.js' import { supportsGoodTextCharPos -} from '../common/browser.js'; +} from '../common/browser.js' -let svgCanvas = null; +let svgCanvas = null /** * @function module:text-actions.init @@ -25,8 +24,8 @@ let svgCanvas = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; -}; + svgCanvas = canvas +} /** * Group: Text edit functions @@ -35,16 +34,16 @@ export const init = function (canvas) { * @memberof module:svgcanvas.SvgCanvas# */ export const textActionsMethod = (function () { - let curtext; - let textinput; - let cursor; - let selblock; - let blinker; - let chardata = []; - let textbb; // , transbb; - let matrix; - let lastX; let lastY; - let allowDbl; + let curtext + let textinput + let cursor + let selblock + let blinker + let chardata = [] + let textbb // , transbb; + let matrix + let lastX; let lastY + let allowDbl /** * @@ -52,42 +51,42 @@ export const textActionsMethod = (function () { * @returns {void} */ function setCursor (index) { - const empty = (textinput.value === ''); - textinput.focus(); + const empty = (textinput.value === '') + textinput.focus() if (!arguments.length) { if (empty) { - index = 0; + index = 0 } else { - if (textinput.selectionEnd !== textinput.selectionStart) { return; } - index = textinput.selectionEnd; + if (textinput.selectionEnd !== textinput.selectionStart) { return } + index = textinput.selectionEnd } } - const charbb = chardata[index]; + const charbb = chardata[index] if (!empty) { - textinput.setSelectionRange(index, index); + textinput.setSelectionRange(index, index) } - cursor = getElem('text_cursor'); + cursor = getElem('text_cursor') if (!cursor) { - cursor = document.createElementNS(NS.SVG, 'line'); + cursor = document.createElementNS(NS.SVG, 'line') assignAttributes(cursor, { id: 'text_cursor', stroke: '#333', 'stroke-width': 1 - }); - getElem('selectorParentGroup').append(cursor); + }) + getElem('selectorParentGroup').append(cursor) } if (!blinker) { blinker = setInterval(function () { - const show = (cursor.getAttribute('display') === 'none'); - cursor.setAttribute('display', show ? 'inline' : 'none'); - }, 600); + 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)); + const startPt = ptToScreen(charbb.x, textbb.y) + const endPt = ptToScreen(charbb.x, (textbb.y + textbb.height)) assignAttributes(cursor, { x1: startPt.x, @@ -96,9 +95,9 @@ export const textActionsMethod = (function () { y2: endPt.y, visibility: 'visible', display: 'inline' - }); + }) - if (selblock) { selblock.setAttribute('d', ''); } + if (selblock) { selblock.setAttribute('d', '') } } /** @@ -110,45 +109,45 @@ export const textActionsMethod = (function () { */ function setSelection (start, end, skipInput) { if (start === end) { - setCursor(end); - return; + setCursor(end) + return } if (!skipInput) { - textinput.setSelectionRange(start, end); + textinput.setSelectionRange(start, end) } - selblock = getElem('text_selectblock'); + selblock = getElem('text_selectblock') if (!selblock) { - selblock = document.createElementNS(NS.SVG, 'path'); + selblock = document.createElementNS(NS.SVG, 'path') assignAttributes(selblock, { id: 'text_selectblock', fill: 'green', opacity: 0.5, style: 'pointer-events:none' - }); - getElem('selectorParentGroup').append(selblock); + }) + getElem('selectorParentGroup').append(selblock) } - const startbb = chardata[start]; - const endbb = chardata[end]; + const startbb = chardata[start] + const endbb = chardata[end] - cursor.setAttribute('visibility', 'hidden'); + cursor.setAttribute('visibility', 'hidden') - const tl = ptToScreen(startbb.x, textbb.y); - const tr = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y); - const bl = ptToScreen(startbb.x, textbb.y + textbb.height); - const br = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y + textbb.height); + const tl = ptToScreen(startbb.x, textbb.y) + const tr = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y) + const bl = ptToScreen(startbb.x, textbb.y + textbb.height) + const 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'; +' ' + bl.x + ',' + bl.y + 'z' assignAttributes(selblock, { d: dstr, display: 'inline' - }); + }) } /** @@ -159,29 +158,29 @@ export const textActionsMethod = (function () { */ function getIndexFromPoint (mouseX, mouseY) { // Position cursor here - const pt = svgCanvas.getSvgRoot().createSVGPoint(); - pt.x = mouseX; - pt.y = mouseY; + const pt = svgCanvas.getSvgRoot().createSVGPoint() + pt.x = mouseX + pt.y = mouseY // No content, so return 0 - if (chardata.length === 1) { return 0; } + if (chardata.length === 1) { return 0 } // Determine if cursor should be on left or right of character - let charpos = curtext.getCharNumAtPosition(pt); + let charpos = curtext.getCharNumAtPosition(pt) if (charpos < 0) { // Out of text range, look at mouse coords - charpos = chardata.length - 2; + charpos = chardata.length - 2 if (mouseX <= chardata[0].x) { - charpos = 0; + charpos = 0 } } else if (charpos >= chardata.length - 2) { - charpos = chardata.length - 2; + charpos = chardata.length - 2 } - const charbb = chardata[charpos]; - const mid = charbb.x + (charbb.width / 2); + const charbb = chardata[charpos] + const mid = charbb.x + (charbb.width / 2) if (mouseX > mid) { - charpos++; + charpos++ } - return charpos; + return charpos } /** @@ -191,7 +190,7 @@ export const textActionsMethod = (function () { * @returns {void} */ function setCursorFromPoint (mouseX, mouseY) { - setCursor(getIndexFromPoint(mouseX, mouseY)); + setCursor(getIndexFromPoint(mouseX, mouseY)) } /** @@ -202,12 +201,12 @@ export const textActionsMethod = (function () { * @returns {void} */ function setEndSelectionFromPoint (x, y, apply) { - const i1 = textinput.selectionStart; - const i2 = getIndexFromPoint(x, y); + 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); + const start = Math.min(i1, i2) + const end = Math.max(i1, i2) + setSelection(start, end, !apply) } /** @@ -220,18 +219,18 @@ export const textActionsMethod = (function () { const out = { x: xIn, y: yIn - }; - const zoom = svgCanvas.getZoom(); - out.x /= zoom; - out.y /= zoom; + } + const zoom = svgCanvas.getZoom() + out.x /= zoom + out.y /= zoom if (matrix) { - const pt = transformPoint(out.x, out.y, matrix.inverse()); - out.x = pt.x; - out.y = pt.y; + const pt = transformPoint(out.x, out.y, matrix.inverse()) + out.x = pt.x + out.y = pt.y } - return out; + return out } /** @@ -244,18 +243,18 @@ export const textActionsMethod = (function () { const out = { x: xIn, y: yIn - }; + } if (matrix) { - const pt = transformPoint(out.x, out.y, matrix); - out.x = pt.x; - out.y = pt.y; + const pt = transformPoint(out.x, out.y, matrix) + out.x = pt.x + out.y = pt.y } - const zoom = svgCanvas.getZoom(); - out.x *= zoom; - out.y *= zoom; + const zoom = svgCanvas.getZoom() + out.x *= zoom + out.y *= zoom - return out; + return out } /** @@ -264,8 +263,8 @@ export const textActionsMethod = (function () { * @returns {void} */ function selectAll (evt) { - setSelection(0, curtext.textContent.length); - evt.target.removeEventListener('click', selectAll); + setSelection(0, curtext.textContent.length) + evt.target.removeEventListener('click', selectAll) } /** @@ -274,26 +273,26 @@ export const textActionsMethod = (function () { * @returns {void} */ function selectWord (evt) { - if (!allowDbl || !curtext) { return; } - const zoom = svgCanvas.getZoom(); - const ept = transformPoint(evt.pageX, evt.pageY, svgCanvas.getrootSctm()); - const mouseX = ept.x * zoom; - const mouseY = ept.y * zoom; - const pt = screenToPt(mouseX, mouseY); + if (!allowDbl || !curtext) { return } + const zoom = svgCanvas.getZoom() + const ept = transformPoint(evt.pageX, evt.pageY, svgCanvas.getrootSctm()) + const mouseX = ept.x * zoom + const mouseY = ept.y * zoom + 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); + 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 - evt.target.addEventListener('click', selectAll); + evt.target.addEventListener('click', selectAll) setTimeout(function () { - evt.target.removeEventListener('click', selectAll); - }, 300); + evt.target.removeEventListener('click', selectAll) + }, 300) } return /** @lends module:svgcanvas.SvgCanvas#textActions */ { @@ -304,16 +303,16 @@ export const textActionsMethod = (function () { * @returns {void} */ select (target, x, y) { - curtext = target; - svgCanvas.textActions.toEditMode(x, y); + curtext = target + svgCanvas.textActions.toEditMode(x, y) }, /** * @param {Element} elem * @returns {void} */ start (elem) { - curtext = elem; - svgCanvas.textActions.toEditMode(); + curtext = elem + svgCanvas.textActions.toEditMode() }, /** * @param {external:MouseEvent} evt @@ -323,12 +322,12 @@ export const textActionsMethod = (function () { * @returns {void} */ mouseDown (evt, mouseTarget, startX, startY) { - const pt = screenToPt(startX, startY); + const pt = screenToPt(startX, startY) - textinput.focus(); - setCursorFromPoint(pt.x, pt.y); - lastX = startX; - lastY = startY; + textinput.focus() + setCursorFromPoint(pt.x, pt.y) + lastX = startX + lastY = startY // TODO: Find way to block native selection }, @@ -338,8 +337,8 @@ export const textActionsMethod = (function () { * @returns {void} */ mouseMove (mouseX, mouseY) { - const pt = screenToPt(mouseX, mouseY); - setEndSelectionFromPoint(pt.x, pt.y); + const pt = screenToPt(mouseX, mouseY) + setEndSelectionFromPoint(pt.x, pt.y) }, /** * @param {external:MouseEvent} evt @@ -348,9 +347,9 @@ export const textActionsMethod = (function () { * @returns {void} */ mouseUp (evt, mouseX, mouseY) { - const pt = screenToPt(mouseX, mouseY); + const pt = screenToPt(mouseX, mouseY) - setEndSelectionFromPoint(pt.x, pt.y, true); + 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 @@ -365,7 +364,7 @@ export const textActionsMethod = (function () { mouseY < lastY + 2 && mouseY > lastY - 2 ) { - svgCanvas.textActions.toSelectMode(true); + svgCanvas.textActions.toSelectMode(true) } }, /** @@ -380,16 +379,16 @@ export const textActionsMethod = (function () { * @returns {void} */ toEditMode (x, y) { - allowDbl = false; - svgCanvas.setCurrentMode('textedit'); - svgCanvas.selectorManager.requestSelector(curtext).showGrips(false); + allowDbl = false + svgCanvas.setCurrentMode('textedit') + svgCanvas.selectorManager.requestSelector(curtext).showGrips(false) // Make selector group accept clicks - /* const selector = */ svgCanvas.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 selector = */ svgCanvas.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; - svgCanvas.textActions.init(); + svgCanvas.textActions.init() - curtext.style.cursor = 'text'; + curtext.style.cursor = 'text' // if (supportsEditableText()) { // curtext.setAttribute('editable', 'simple'); @@ -397,15 +396,15 @@ export const textActionsMethod = (function () { // } if (!arguments.length) { - setCursor(); + setCursor() } else { - const pt = screenToPt(x, y); - setCursorFromPoint(pt.x, pt.y); + const pt = screenToPt(x, y) + setCursorFromPoint(pt.x, pt.y) } setTimeout(function () { - allowDbl = true; - }, 300); + allowDbl = true + }, 300) }, /** * @param {boolean|Element} selectElem @@ -413,28 +412,28 @@ export const textActionsMethod = (function () { * @returns {void} */ toSelectMode (selectElem) { - svgCanvas.setCurrentMode('select'); - clearInterval(blinker); - blinker = null; - if (selblock) { selblock.setAttribute('display', 'none'); } - if (cursor) { cursor.setAttribute('visibility', 'hidden'); } - curtext.style.cursor = 'move'; + svgCanvas.setCurrentMode('select') + clearInterval(blinker) + blinker = null + if (selblock) { selblock.setAttribute('display', 'none') } + if (cursor) { cursor.setAttribute('visibility', 'hidden') } + curtext.style.cursor = 'move' if (selectElem) { - svgCanvas.clearSelection(); - curtext.style.cursor = 'move'; + svgCanvas.clearSelection() + curtext.style.cursor = 'move' - svgCanvas.call('selected', [ curtext ]); - svgCanvas.addToSelection([ curtext ], true); + svgCanvas.call('selected', [curtext]) + svgCanvas.addToSelection([curtext], true) } if (curtext && !curtext.textContent.length) { // No content, so delete - svgCanvas.deleteSelectedElements(); + svgCanvas.deleteSelectedElements() } - textinput.blur(); + textinput.blur() - curtext = false; + curtext = false // if (supportsEditableText()) { // curtext.removeAttribute('editable'); @@ -445,14 +444,14 @@ export const textActionsMethod = (function () { * @returns {void} */ setInputElem (elem) { - textinput = elem; + textinput = elem }, /** * @returns {void} */ clear () { if (svgCanvas.getCurrentMode() === 'textedit') { - svgCanvas.textActions.toSelectMode(); + svgCanvas.textActions.toSelectMode() } }, /** @@ -460,8 +459,8 @@ export const textActionsMethod = (function () { * @returns {void} */ init (_inputElem) { - if (!curtext) { return; } - let i; let end; + if (!curtext) { return } + let i; let end // if (supportsEditableText()) { // curtext.select(); // return; @@ -469,43 +468,43 @@ export const textActionsMethod = (function () { if (!curtext.parentNode) { // Result of the ffClone, need to get correct element - const selectedElements = svgCanvas.getSelectedElements(); - curtext = selectedElements[0]; - svgCanvas.selectorManager.requestSelector(curtext).showGrips(false); + const selectedElements = svgCanvas.getSelectedElements() + curtext = selectedElements[0] + svgCanvas.selectorManager.requestSelector(curtext).showGrips(false) } - const str = curtext.textContent; - const len = str.length; + const str = curtext.textContent + const len = str.length - const xform = curtext.getAttribute('transform'); + const xform = curtext.getAttribute('transform') - textbb = utilsGetBBox(curtext); + textbb = utilsGetBBox(curtext) - matrix = xform ? getMatrix(curtext) : null; + matrix = xform ? getMatrix(curtext) : null - chardata = []; - chardata.length = len; - textinput.focus(); + chardata = [] + chardata.length = len + textinput.focus() - curtext.removeEventListener("dblclick", selectWord); - curtext.addEventListener("dblclick", selectWord); + curtext.removeEventListener('dblclick', selectWord) + curtext.addEventListener('dblclick', selectWord) if (!len) { - end = { x: textbb.x + (textbb.width / 2), width: 0 }; + end = { x: textbb.x + (textbb.width / 2), width: 0 } } for (i = 0; i < len; i++) { - const start = curtext.getStartPositionOfChar(i); - end = curtext.getEndPositionOfChar(i); + const start = curtext.getStartPositionOfChar(i) + end = curtext.getEndPositionOfChar(i) if (!supportsGoodTextCharPos()) { - const zoom = svgCanvas.getZoom(); - const offset = svgCanvas.contentW * zoom; - start.x -= offset; - end.x -= offset; + const zoom = svgCanvas.getZoom() + const offset = svgCanvas.contentW * zoom + start.x -= offset + end.x -= offset - start.x /= zoom; - end.x /= zoom; + start.x /= zoom + end.x /= zoom } // Get a "bbox" equivalent for each character. Uses the @@ -517,15 +516,15 @@ export const textActionsMethod = (function () { 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); + }) + setSelection(textinput.selectionStart, textinput.selectionEnd, true) } - }; -}()); + } +}()) diff --git a/src/svgcanvas/undo.js b/src/svgcanvas/undo.js index 37756dfc..b7399914 100644 --- a/src/svgcanvas/undo.js +++ b/src/svgcanvas/undo.js @@ -4,23 +4,23 @@ * @license MIT * @copyright 2011 Jeff Schiller */ -import * as draw from './draw.js'; -import * as hstry from './history.js'; +import * as draw from './draw.js' +import * as hstry from './history.js' import { getRotationAngle, getBBox as utilsGetBBox, isNullish, setHref, getStrokedBBoxDefaultVisible -} from './utilities.js'; +} from './utilities.js' import { isGecko -} from '../common/browser.js'; +} from '../common/browser.js' import { transformPoint, transformListToTransform -} from './math.js'; +} from './math.js' const { UndoManager, HistoryEventTypes -} = hstry; +} = hstry -let svgCanvas = null; +let svgCanvas = null /** * @function module:undo.init @@ -28,9 +28,9 @@ let svgCanvas = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; - canvas.undoMgr = getUndoManager(); -}; + svgCanvas = canvas + canvas.undoMgr = getUndoManager() +} export const getUndoManager = () => { return new UndoManager({ @@ -41,70 +41,70 @@ export const getUndoManager = () => { * @returns {void} */ handleHistoryEvent (eventType, cmd) { - const EventTypes = HistoryEventTypes; + const EventTypes = HistoryEventTypes // TODO: handle setBlurOffsets. if (eventType === EventTypes.BEFORE_UNAPPLY || eventType === EventTypes.BEFORE_APPLY) { - svgCanvas.clearSelection(); + svgCanvas.clearSelection() } else if (eventType === EventTypes.AFTER_APPLY || eventType === EventTypes.AFTER_UNAPPLY) { - const elems = cmd.elements(); - svgCanvas.pathActions.clear(); - svgCanvas.call('changed', elems); - const cmdType = cmd.type(); - const isApply = (eventType === EventTypes.AFTER_APPLY); + const elems = cmd.elements() + svgCanvas.pathActions.clear() + svgCanvas.call('changed', elems) + const cmdType = cmd.type() + const isApply = (eventType === EventTypes.AFTER_APPLY) if (cmdType === 'MoveElementCommand') { - const parent = isApply ? cmd.newParent : cmd.oldParent; + const parent = isApply ? cmd.newParent : cmd.oldParent if (parent === svgCanvas.getSvgContent()) { - draw.identifyLayers(); + draw.identifyLayers() } } else if (cmdType === 'InsertElementCommand' || cmdType === 'RemoveElementCommand') { if (cmd.parent === svgCanvas.getSvgContent()) { - draw.identifyLayers(); + draw.identifyLayers() } if (cmdType === 'InsertElementCommand') { if (isApply) { - svgCanvas.restoreRefElements(cmd.elem); + svgCanvas.restoreRefElements(cmd.elem) } } else if (!isApply) { - svgCanvas.restoreRefElements(cmd.elem); + svgCanvas.restoreRefElements(cmd.elem) } if (cmd.elem && cmd.elem.tagName === 'use') { - svgCanvas.setUseData(cmd.elem); + svgCanvas.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 === svgCanvas.getSvgContent() ) { - draw.identifyLayers(); + draw.identifyLayers() } - const values = isApply ? cmd.newValues : cmd.oldValues; + const values = isApply ? cmd.newValues : cmd.oldValues // If stdDeviation was changed, update the blur. if (values.stdDeviation) { - svgCanvas.setBlurOffsets(cmd.elem.parentNode, values.stdDeviation); + svgCanvas.setBlurOffsets(cmd.elem.parentNode, values.stdDeviation) } - if (cmd.elem.tagName === 'text'){ - const [ dx, dy ] = [ cmd.newValues.x - cmd.oldValues.x, - cmd.newValues.y - cmd.oldValues.y ]; + if (cmd.elem.tagName === 'text') { + const [dx, dy] = [cmd.newValues.x - cmd.oldValues.x, + cmd.newValues.y - cmd.oldValues.y] - const tspans = cmd.elem.children; + const tspans = cmd.elem.children - for (let i = 0; i < tspans.length; i++){ - let x = Number(tspans[i].getAttribute('x')); - let y = Number(tspans[i].getAttribute('y')); + for (let i = 0; i < tspans.length; i++) { + let x = Number(tspans[i].getAttribute('x')) + let y = Number(tspans[i].getAttribute('y')) - const unapply = (eventType === EventTypes.AFTER_UNAPPLY); - x = unapply? x - dx: x + dx; - y = unapply? y - dy: y + dy; + const unapply = (eventType === EventTypes.AFTER_UNAPPLY) + x = unapply ? x - dx : x + dx + y = unapply ? y - dy : y + dy - tspans[i].setAttribute('x', x); - tspans[i].setAttribute('y', y); + tspans[i].setAttribute('x', x) + tspans[i].setAttribute('y', y) } } } } } - }); -}; + }) +} /** * Hack for Firefox bugs where text element features aren't updated or get @@ -117,15 +117,15 @@ export const getUndoManager = () => { * @returns {Element} Cloned element */ export const ffClone = function (elem) { - if (!isGecko()) { return elem; } - const clone = elem.cloneNode(true); - elem.before(clone); - elem.remove(); - svgCanvas.selectorManager.releaseSelector(elem); - svgCanvas.setSelectedElements(0, clone); - svgCanvas.selectorManager.requestSelector(clone).showGrips(true); - return clone; -}; + if (!isGecko()) { return elem } + const clone = elem.cloneNode(true) + elem.before(clone) + elem.remove() + svgCanvas.selectorManager.releaseSelector(elem) + svgCanvas.setSelectedElements(0, clone) + svgCanvas.selectorManager.requestSelector(clone).showGrips(true) + return clone +} /** * This function makes the changes to the elements. It does not add the change @@ -136,43 +136,43 @@ export const ffClone = function (elem) { * @returns {void} */ export const changeSelectedAttributeNoUndoMethod = function (attr, newValue, elems) { - const selectedElements = svgCanvas.getSelectedElements(); - const zoom = svgCanvas.getZoom(); + const selectedElements = svgCanvas.getSelectedElements() + const zoom = svgCanvas.getZoom() if (svgCanvas.getCurrentMode() === 'pathedit') { // Editing node - svgCanvas.pathActions.moveNode(attr, newValue); + svgCanvas.pathActions.moveNode(attr, newValue) } - elems = elems || selectedElements; - let i = elems.length; - const noXYElems = [ 'g', 'polyline', 'path' ]; + 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; } + 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; - svgCanvas.moveSelectedElements(diffX * zoom, diffY * zoom, true); - continue; + const bbox = getStrokedBBoxDefaultVisible([elem]) + const diffX = attr === 'x' ? newValue - bbox.x : 0 + const diffY = attr === 'y' ? newValue - bbox.y : 0 + svgCanvas.moveSelectedElements(diffX * zoom, diffY * zoom, 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 = ''; } + 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; + elem.textContent = newValue // FF bug occurs on on rotated elements if ((/rotate/).test(elem.getAttribute('transform'))) { - elem = ffClone(elem); + 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 @@ -189,13 +189,13 @@ export const changeSelectedAttributeNoUndoMethod = function (attr, newValue, ele // elem.setAttribute('y', elem.getAttribute('y') - dy); // } } else if (attr === '#href') { - setHref(elem, newValue); + setHref(elem, newValue) } else if (newValue) { - elem.setAttribute(attr, newValue); + elem.setAttribute(attr, newValue) } else if (typeof newValue === 'number') { - elem.setAttribute(attr, newValue); + elem.setAttribute(attr, newValue) } else { - elem.removeAttribute(attr); + elem.removeAttribute(attr) } // Go into "select" mode for text changes @@ -203,7 +203,7 @@ export const changeSelectedAttributeNoUndoMethod = function (attr, newValue, ele // font-size can get reset to their old value, ultimately by svgEditor.updateContextPanel(), // after calling textActions.toSelectMode() below if (svgCanvas.getCurrentMode() === 'textedit' && attr !== '#text' && elem.textContent.length) { - svgCanvas.textActions.toSelectMode(elem); + svgCanvas.textActions.toSelectMode(elem) } // if (i === 0) { @@ -215,8 +215,8 @@ export const changeSelectedAttributeNoUndoMethod = function (attr, newValue, ele if (isGecko() && elem.nodeName === 'text' && (/rotate/).test(elem.getAttribute('transform')) && - (String(newValue).startsWith('url') || ([ 'font-size', 'font-family', 'x', 'y' ].includes(attr) && elem.textContent))) { - elem = ffClone(elem); + (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 @@ -226,38 +226,38 @@ export const changeSelectedAttributeNoUndoMethod = function (attr, newValue, ele setTimeout(function () { // Due to element replacement, this element may no longer // be part of the DOM - if (!elem.parentNode) { return; } - svgCanvas.selectorManager.requestSelector(elem).resize(); - }, 0); + if (!elem.parentNode) { return } + svgCanvas.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); + const angle = getRotationAngle(elem) if (angle !== 0 && attr !== 'transform') { - const tlist = elem.transform?.baseVal; - let n = tlist.numberOfItems; + const tlist = elem.transform?.baseVal + let n = tlist.numberOfItems while (n--) { - const xform = tlist.getItem(n); + const xform = tlist.getItem(n) if (xform.type === 4) { // remove old rotate - tlist.removeItem(n); + tlist.removeItem(n) - const box = utilsGetBBox(elem); + const box = utilsGetBBox(elem) const center = transformPoint( box.x + box.width / 2, box.y + box.height / 2, transformListToTransform(tlist).matrix - ); - const cx = center.x; - const cy = center.y; - const newrot = svgCanvas.getSvgRoot().createSVGTransform(); - newrot.setRotate(angle, cx, cy); - tlist.insertItemBefore(newrot, n); - break; + ) + const cx = center.x + const cy = center.y + const newrot = svgCanvas.getSvgRoot().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. @@ -271,16 +271,16 @@ export const changeSelectedAttributeNoUndoMethod = function (attr, newValue, ele * @returns {void} */ export const changeSelectedAttributeMethod = function (attr, val, elems) { - const selectedElements = svgCanvas.getSelectedElements(); - elems = elems || selectedElements; - svgCanvas.undoMgr.beginUndoableChange(attr, elems); + const selectedElements = svgCanvas.getSelectedElements() + elems = elems || selectedElements + svgCanvas.undoMgr.beginUndoableChange(attr, elems) // const i = elems.length; - changeSelectedAttributeNoUndoMethod(attr, val, elems); + changeSelectedAttributeNoUndoMethod(attr, val, elems) - const batchCmd = svgCanvas.undoMgr.finishUndoableChange(); + const batchCmd = svgCanvas.undoMgr.finishUndoableChange() if (!batchCmd.isEmpty()) { // svgCanvas.addCommandToHistory(batchCmd); - svgCanvas.undoMgr.addCommandToHistory(batchCmd); + svgCanvas.undoMgr.addCommandToHistory(batchCmd) } -}; +} diff --git a/src/svgcanvas/utilities.js b/src/svgcanvas/utilities.js index 40cd6a20..fbc78ae8 100644 --- a/src/svgcanvas/utilities.js +++ b/src/svgcanvas/utilities.js @@ -6,20 +6,20 @@ * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller */ -import { NS } from './namespaces.js'; -import { setUnitAttr, getTypeMap } from '../common/units.js'; +import { NS } from './namespaces.js' +import { setUnitAttr, getTypeMap } from '../common/units.js' import { hasMatrixTransform, transformListToTransform, transformBox -} from './math.js'; -import { getClosest, mergeDeep } from '../editor/components/jgraduate/Util.js'; +} from './math.js' +import { getClosest, mergeDeep } from '../editor/components/jgraduate/Util.js' // 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 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 svgCanvas = null; -let svgroot_ = null; +let svgCanvas = null +let svgroot_ = null /** * Object with the following keys/values. @@ -81,9 +81,9 @@ let svgroot_ = null; * @returns {void} */ export const init = function (canvas) { - svgCanvas = canvas; - svgroot_ = canvas.getSvgRoot(); -}; + svgCanvas = canvas + svgroot_ = canvas.getSvgRoot() +} /** * Used to prevent the [Billion laughs attack]{@link https://en.wikipedia.org/wiki/Billion_laughs_attack}. @@ -93,9 +93,9 @@ export const init = function (canvas) { * @todo This might be needed in other places `parseFromString` is used even without LGTM flagging */ export const dropXMLInternalSubset = (str) => { - return str.replace(/(<!DOCTYPE\s+\w*\s*\[).*(\?]>)/, '$1$2'); + 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. @@ -112,8 +112,8 @@ export const toXml = function (str) { .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') - .replace(/'/g, '''); // Note: `'` is XML only -}; + .replace(/'/g, ''') // Note: `'` is XML only +} // 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. @@ -128,10 +128,10 @@ export const toXml = function (str) { * @param {string} input * @returns {string} Base64 output */ -export function encode64(input) { +export function encode64 (input) { // base64 strings are 4/3 larger than the original string - input = encodeUTF8(input); // convert non-ASCII characters - return window.btoa(input); // Use native if available + input = encodeUTF8(input) // convert non-ASCII characters + return window.btoa(input) // Use native if available } /** @@ -140,8 +140,8 @@ export function encode64(input) { * @param {string} input Base64-encoded input * @returns {string} Decoded output */ -export function decode64(input) { - return decodeUTF8(window.atob(input)); +export function decode64 (input) { + return decodeUTF8(window.atob(input)) } /** @@ -149,8 +149,8 @@ export function decode64(input) { * @param {string} argString * @returns {string} */ -export function decodeUTF8(argString) { - return decodeURIComponent(escape(argString)); +export 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 @@ -160,8 +160,8 @@ export function decodeUTF8(argString) { * @returns {string} */ export const encodeUTF8 = function (argString) { - return unescape(encodeURIComponent(argString)); -}; + return unescape(encodeURIComponent(argString)) +} /** * Convert dataURL to object URL. @@ -171,24 +171,24 @@ export const encodeUTF8 = function (argString) { */ export const dataURLToObjectURL = function (dataurl) { if (typeof Uint8Array === 'undefined' || typeof Blob === 'undefined' || typeof URL === 'undefined' || !URL.createObjectURL) { - return ''; + return '' } - const arr = dataurl.split(','); - const mime = arr[0].match(/:(.*?);/)[1]; - const bstr = atob(arr[1]); + const arr = dataurl.split(',') + const mime = arr[0].match(/:(.*?);/)[1] + const bstr = atob(arr[1]) /* const [prefix, suffix] = dataurl.split(','), {groups: {mime}} = prefix.match(/:(?<mime>.*?);/), bstr = atob(suffix); */ - let n = bstr.length; - const u8arr = new Uint8Array(n); + let n = bstr.length + const u8arr = new Uint8Array(n) while (n--) { - u8arr[n] = bstr.charCodeAt(n); + u8arr[n] = bstr.charCodeAt(n) } - const blob = new Blob([ u8arr ], { type: mime }); - return URL.createObjectURL(blob); -}; + const blob = new Blob([u8arr], { type: mime }) + return URL.createObjectURL(blob) +} /** * Get object URL for a blob object. @@ -198,21 +198,21 @@ export const dataURLToObjectURL = function (dataurl) { */ export const createObjectURL = function (blob) { if (!blob || typeof URL === 'undefined' || !URL.createObjectURL) { - return ''; + return '' } - return URL.createObjectURL(blob); -}; + return URL.createObjectURL(blob) +} /** * @property {string} blankPageObjectURL */ export const blankPageObjectURL = (function () { if (typeof Blob === 'undefined') { - return ''; + return '' } - const blob = new Blob([ '<html><head><title>SVG-edit ' ], { type: 'text/html' }); - return createObjectURL(blob); -})(); + const blob = new Blob(['SVG-edit '], { type: 'text/html' }) + return createObjectURL(blob) +})() /** * Converts a string to use XML references (for non-ASCII). @@ -222,12 +222,12 @@ export const blankPageObjectURL = (function () { */ export const convertToXMLReferences = function (input) { let output = ''; - [ ...input ].forEach((ch) => { - const c = ch.charCodeAt(); - output += (c <= 127) ? ch : `&#${c};`; - }); - return output; -}; + [...input].forEach((ch) => { + const c = ch.charCodeAt() + output += (c <= 127) ? ch : `&#${c};` + }) + return output +} /** * Cross-browser compatible method of converting a string to an XML tree. @@ -239,21 +239,21 @@ export const convertToXMLReferences = function (input) { */ export const text2xml = function (sXML) { if (sXML.includes('` element, creating it first if necessary */ export const findDefs = function () { - const svgElement = svgCanvas.getSvgContent(); - let defs = svgElement.getElementsByTagNameNS(NS.SVG, 'defs'); + const svgElement = svgCanvas.getSvgContent() + let defs = svgElement.getElementsByTagNameNS(NS.SVG, 'defs') if (defs.length > 0) { - defs = defs[0]; + defs = defs[0] } else { - defs = svgElement.ownerDocument.createElementNS(NS.SVG, 'defs'); + 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.insertBefore(defs, svgElement.firstChild.nextSibling) // svgElement.firstChild.nextSibling.before(defs); // Not safe } else { - svgElement.append(defs); + svgElement.append(defs) } } - return defs; -}; + return defs +} // TODO(codedread): Consider moving the next to functions to bbox.js @@ -393,76 +393,76 @@ export const findDefs = function () { * @returns {module:utilities.BBoxObject} A BBox-like object */ export const getPathBBox = function (path) { - const seglist = path.pathSegList; - const tot = seglist.numberOfItems; + const seglist = path.pathSegList + const tot = seglist.numberOfItems - const bounds = [ [], [] ]; - const start = seglist.getItem(0); - let P0 = [ start.x, start.y ]; + 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 ]; - const P2 = [ seg.x2, seg.y2 ]; - const 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); + t ** 3 * P3[j] } } - 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; + 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] + const P2 = [seg.x2, seg.y2] + const 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, convert it to be more @@ -472,64 +472,64 @@ export const getPathBBox = function (path) { * @returns {module:utilities.BBoxObject} Bounding box object */ export const getBBox = function (elem) { - const selected = elem || svgCanvas.getSelectedElements()[0]; - if (elem.nodeType !== 1) { return null; } - const elname = selected.nodeName; + const selected = elem || svgCanvas.getSelectedElements()[0] + if (elem.nodeType !== 1) { return null } + const elname = selected.nodeName - let ret = null; + 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': - case 'g': - case 'a': - if (selected.getBBox) { - ret = selected.getBBox(); - } - break; - default: + 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': + case 'g': + case 'a': + if (selected.getBBox) { + ret = selected.getBBox() + } + break + default: - if (elname === 'use') { - ret = selected.getBBox(); // , true); - } else if (visElemsArr.includes(elname)) { - if (selected) { - try { - ret = selected.getBBox(); - } catch (err) { + if (elname === 'use') { + ret = selected.getBBox() // , true); + } 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 { + 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 = getClosest(selected.parentNode, 'foreignObject'); - if (fo.length && fo[0].getBBox) { - ret = fo[0].getBBox(); + const fo = getClosest(selected.parentNode, 'foreignObject') + if (fo.length && fo[0].getBBox) { + ret = fo[0].getBBox() + } } } - } } if (ret) { - ret = bboxToObj(ret); + ret = bboxToObj(ret) } // get the bounding box from the DOM (which is in that element's coordinate system) - return ret; -}; + return ret +} /** * @typedef {GenericArray} module:utilities.PathSegmentArray @@ -546,17 +546,17 @@ export const getBBox = function (elem) { * @returns {string} The converted path d attribute. */ export const getPathDFromSegments = function (pathSegments) { - let d = ''; + let d = '' - pathSegments.forEach(function([ singleChar, pts ], _j){ - d += singleChar; + pathSegments.forEach(function ([singleChar, pts], _j) { + d += singleChar for (let i = 0; i < pts.length; i += 2) { - d += (pts[i] + ',' + pts[i + 1]) + ' '; + d += (pts[i] + ',' + pts[i + 1]) + ' ' } - }); + }) - return d; -}; + return d +} /** * Make a path 'd' attribute from a simple SVG element shape. @@ -566,83 +566,83 @@ export const getPathDFromSegments = function (pathSegments) { */ export const getPathDFromElement = function (elem) { // Possibly the cubed root of 6, but 1.81 works best - let num = 1.81; - let d; let rx; let ry; + let num = 1.81 + let d; let rx; let ry switch (elem.tagName) { - case 'ellipse': - case 'circle': { - rx = Number(elem.getAttribute('rx')); - ry = Number(elem.getAttribute('ry')); - const cx = Number(elem.getAttribute('cx')); - const cy = Number(elem.getAttribute('cy')); - if (elem.tagName === 'circle' && elem.hasAttribute('r')) { - ry = Number(elem.getAttribute('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': { - const x1 = elem.getAttribute('x1'); - const y1 = elem.getAttribute('y1'); - const x2 = elem.getAttribute('x2'); - const y2 = elem.getAttribute('y2'); - d = 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2; - } - break; - case 'polyline': - d = 'M' + elem.getAttribute('points'); - break; - case 'polygon': - d = 'M' + elem.getAttribute('points') + ' Z'; - break; - case 'rect': { - rx = Number(elem.getAttribute('rx')); - ry = Number(elem.getAttribute('ry')); - const b = elem.getBBox(); - const { x, y } = b; - const w = b.width; - const h = b.height; - num = 4 - num; // Why? Because! - - d = (!rx && !ry) - // Regular rect - ? getPathDFromSegments([ - [ 'M', [ x, y ] ], - [ 'L', [ x + w, y ] ], - [ 'L', [ x + w, y + h ] ], - [ 'L', [ x, y + h ] ], - [ 'L', [ x, y ] ], - [ 'Z', [] ] + case 'ellipse': + case 'circle': { + rx = Number(elem.getAttribute('rx')) + ry = Number(elem.getAttribute('ry')) + const cx = Number(elem.getAttribute('cx')) + const cy = Number(elem.getAttribute('cy')) + if (elem.tagName === 'circle' && elem.hasAttribute('r')) { + ry = Number(elem.getAttribute('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', []] ]) - : 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; - } default: - break; + break + } case 'path': + d = elem.getAttribute('d') + break + case 'line': { + const x1 = elem.getAttribute('x1') + const y1 = elem.getAttribute('y1') + const x2 = elem.getAttribute('x2') + const y2 = elem.getAttribute('y2') + d = 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2 + } + break + case 'polyline': + d = 'M' + elem.getAttribute('points') + break + case 'polygon': + d = 'M' + elem.getAttribute('points') + ' Z' + break + case 'rect': { + rx = Number(elem.getAttribute('rx')) + ry = Number(elem.getAttribute('ry')) + const b = elem.getBBox() + const { x, y } = b + const w = b.width + const h = b.height + num = 4 - num // Why? Because! + + d = (!rx && !ry) + // Regular rect + ? getPathDFromSegments([ + ['M', [x, y]], + ['L', [x + w, y]], + ['L', [x + w, y + h]], + ['L', [x, y + h]], + ['L', [x, y]], + ['Z', []] + ]) + : 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 + } default: + break } - return d; -}; + return d +} /** * Get a set of attributes from an element that is useful for convertToPath. @@ -654,14 +654,14 @@ export 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? - [ 'marker-start', 'marker-end', 'marker-mid', 'filter', 'clip-path' ].forEach(function(item){ - const a = elem.getAttribute(item); + ['marker-start', 'marker-end', 'marker-mid', 'filter', 'clip-path'].forEach(function (item) { + const a = elem.getAttribute(item) if (a) { - attrs[item] = a; + attrs[item] = a } - }); - return attrs; -}; + }) + return attrs +} /** * Get the BBox of an element-as-path. @@ -675,38 +675,38 @@ export const getBBoxOfElementAsPath = function (elem, addSVGElemensFromJson, pat const path = addSVGElemensFromJson({ element: 'path', attr: getExtraAttributesForConvertToPath(elem) - }); + }) - const eltrans = elem.getAttribute('transform'); + const eltrans = elem.getAttribute('transform') if (eltrans) { - path.setAttribute('transform', eltrans); + path.setAttribute('transform', eltrans) } - const { parentNode } = elem; + const { parentNode } = elem if (elem.nextSibling) { - elem.before(path); + elem.before(path) } else { - parentNode.append(path); + parentNode.append(path) } - const d = getPathDFromElement(elem); + const d = getPathDFromElement(elem) if (d) { - path.setAttribute('d', d); + path.setAttribute('d', d) } else { - path.remove(); + path.remove() } // Get the correct BBox of the new path, then discard it - pathActions.resetOrientation(path); - let bb = false; + pathActions.resetOrientation(path) + let bb = false try { - bb = path.getBBox(); + bb = path.getBBox() } catch (e) { // Firefox fails } - path.remove(); - return bb; -}; + path.remove() + return bb +} /** * Convert selected element to a path. @@ -725,61 +725,61 @@ export const convertToPath = ( elem, attrs, addSVGElemensFromJson, pathActions, clearSelection, addToSelection, hstry, addCommandToHistory ) => { - const batchCmd = new hstry.BatchCommand('Convert element to Path'); + const batchCmd = new hstry.BatchCommand('Convert element to Path') // Any attribute on the element not covered by the passed-in attributes - attrs = mergeDeep(attrs, getExtraAttributesForConvertToPath(elem)); + attrs = mergeDeep(attrs, getExtraAttributesForConvertToPath(elem)) const path = addSVGElemensFromJson({ element: 'path', attr: attrs - }); + }) - const eltrans = elem.getAttribute('transform'); + const eltrans = elem.getAttribute('transform') if (eltrans) { - path.setAttribute('transform', eltrans); + path.setAttribute('transform', eltrans) } - const { id } = elem; - const { parentNode } = elem; + const { id } = elem + const { parentNode } = elem if (elem.nextSibling) { - elem.before(path); + elem.before(path) } else { - parentNode.append(path); + parentNode.append(path) } - const d = getPathDFromElement(elem); + const d = getPathDFromElement(elem) if (d) { - path.setAttribute('d', d); + path.setAttribute('d', d) // Replace the current element with the converted one // Reorient if it has a matrix if (eltrans) { - const tlist = path.transform.baseVal; + const tlist = path.transform.baseVal if (hasMatrixTransform(tlist)) { - pathActions.resetOrientation(path); + pathActions.resetOrientation(path) } } - const { nextSibling } = elem; - batchCmd.addSubCommand(new hstry.RemoveElementCommand(elem, nextSibling, parent)); - batchCmd.addSubCommand(new hstry.InsertElementCommand(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); + clearSelection() + elem.remove() + path.setAttribute('id', id) + path.removeAttribute('visibility') + addToSelection([path], true) - addCommandToHistory(batchCmd); + addCommandToHistory(batchCmd) - return path; + 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; -}; + path.remove() + return null +} /** * Can the bbox be optimized over the native getBBox? The optimized bbox is the same as the native getBBox when @@ -801,11 +801,11 @@ export const convertToPath = ( * @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); +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) } /** @@ -821,43 +821,43 @@ export const getBBoxWithTransform = function (elem, addSVGElemensFromJson, pathA // fine in FF, but not in other browsers (same problem mentioned // in Issue 339 comment #2). - let bb = getBBox(elem); + let bb = getBBox(elem) if (!bb) { - return null; + return null } - const tlist = elem.transform.baseVal; - const angle = getRotationAngleFromTransformList(tlist); - const hasMatrixXForm = hasMatrixTransform(tlist); + const tlist = elem.transform.baseVal + const angle = getRotationAngleFromTransformList(tlist) + const hasMatrixXForm = hasMatrixTransform(tlist) if (angle || hasMatrixXForm) { - let goodBb = false; + 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' ]; + const elemNames = ['ellipse', 'path', 'line', 'polyline', 'polygon'] if (elemNames.includes(elem.tagName)) { - goodBb = getBBoxOfElementAsPath(elem, addSVGElemensFromJson, pathActions); - bb = goodBb; + goodBb = getBBoxOfElementAsPath(elem, addSVGElemensFromJson, pathActions) + bb = goodBb } else if (elem.tagName === 'rect') { // Look for radius - const rx = Number(elem.getAttribute('rx')); - const ry = Number(elem.getAttribute('ry')); + const rx = Number(elem.getAttribute('rx')) + const ry = Number(elem.getAttribute('ry')) if (rx || ry) { - goodBb = getBBoxOfElementAsPath(elem, addSVGElemensFromJson, pathActions); - bb = goodBb; + goodBb = getBBoxOfElementAsPath(elem, addSVGElemensFromJson, pathActions) + bb = goodBb } } } if (!goodBb) { - const { matrix } = transformListToTransform(tlist); - bb = transformBox(bb.x, bb.y, bb.width, bb.height, matrix).aabox; + const { matrix } = transformListToTransform(tlist) + bb = transformBox(bb.x, bb.y, bb.width, bb.height, matrix).aabox } } - return bb; -}; + return bb +} /** * @param {Element} elem @@ -865,9 +865,9 @@ export const getBBoxWithTransform = function (elem, addSVGElemensFromJson, pathA * @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; +function getStrokeOffsetForBBox (elem) { + const sw = elem.getAttribute('stroke-width') + return (!isNaN(sw) && elem.getAttribute('stroke') !== 'none') ? sw / 2 : 0 } /** @@ -887,55 +887,55 @@ function getStrokeOffsetForBBox(elem) { * @returns {module:utilities.BBoxObject|module:math.TransformedBox|DOMRect} A single bounding box object */ export const getStrokedBBox = function (elems, addSVGElemensFromJson, pathActions) { - if (!elems || !elems.length) { return false; } + if (!elems || !elems.length) { return false } - let fullBb; - elems.forEach(function(elem){ - if (fullBb) { return; } - if (!elem.parentNode) { return; } - fullBb = getBBoxWithTransform(elem, addSVGElemensFromJson, pathActions); - }); + let fullBb + elems.forEach(function (elem) { + if (fullBb) { return } + if (!elem.parentNode) { return } + fullBb = getBBoxWithTransform(elem, addSVGElemensFromJson, pathActions) + }) // This shouldn't ever happen... - if (!fullBb) { return null; } + if (!fullBb) { 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; + 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; + const offset = getStrokeOffsetForBBox(elems[0]) + minX -= offset + minY -= offset + maxX += offset + maxY += offset } else { - elems.forEach(function(elem){ - const curBb = getBBoxWithTransform(elem, addSVGElemensFromJson, pathActions); + elems.forEach(function (elem) { + const curBb = getBBoxWithTransform(elem, addSVGElemensFromJson, pathActions) if (curBb) { - const offset = getStrokeOffsetForBBox(elem); - minX = Math.min(minX, curBb.x - offset); - minY = Math.min(minY, curBb.y - offset); + 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); + 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; -}; + 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). @@ -947,19 +947,20 @@ export const getStrokedBBox = function (elems, addSVGElemensFromJson, pathAction */ export const getVisibleElements = function (parentElement) { if (!parentElement) { - const svgContent = svgCanvas.getSvgContent(); - parentElement = svgContent.children[0]; // Prevent layers from being included + const svgContent = svgCanvas.getSvgContent() + parentElement = svgContent.children[0] // Prevent layers from being included } - const contentElems = []; - const children = parentElement.children; - Array.from(children, function (elem) { + const contentElems = [] + const children = parentElement.children + // eslint-disable-next-line array-callback-return + Array.from(children, (elem) => { if (elem.getBBox) { - contentElems.push(elem); + contentElems.push(elem) } - }); - return contentElems.reverse(); -}; + }) + return contentElems.reverse() +} /** * Get the bounding box for one or more stroked and/or transformed elements. @@ -968,13 +969,13 @@ export const getVisibleElements = function (parentElement) { * @returns {module:utilities.BBoxObject} A single bounding box object */ export const getStrokedBBoxDefaultVisible = function (elems) { - if (!elems) { elems = getVisibleElements(); } + if (!elems) { elems = getVisibleElements() } return getStrokedBBox( elems, svgCanvas.addSVGElemensFromJson, svgCanvas.pathActions - ); -}; + ) +} /** * Get the rotation angle of the given transform list. @@ -984,15 +985,15 @@ export const getStrokedBBoxDefaultVisible = function (elems) { * @returns {Float} The angle in degrees or radians */ export const getRotationAngleFromTransformList = (tlist, toRad) => { - if (!tlist) { return 0; } // <svg> element have no tlist + if (!tlist) { return 0 } // <svg> element have no tlist for (let i = 0; i < tlist.numberOfItems; ++i) { - const xform = tlist.getItem(i); + const xform = tlist.getItem(i) if (xform.type === 4) { - return toRad ? xform.angle * Math.PI / 180.0 : xform.angle; + return toRad ? xform.angle * Math.PI / 180.0 : xform.angle } } - return 0.0; -}; + return 0.0 +} /** * Get the rotation angle of the given/selected DOM element. @@ -1002,11 +1003,11 @@ export const getRotationAngleFromTransformList = (tlist, toRad) => { * @returns {Float} The angle in degrees or radians */ export let getRotationAngle = function (elem, toRad) { - const selected = elem || svgCanvas.getSelectedElements()[0]; + const selected = elem || svgCanvas.getSelectedElements()[0] // find the rotation transform (if any) and set it - const tlist = selected.transform?.baseVal; - return getRotationAngleFromTransformList(tlist, toRad); -}; + const tlist = selected.transform?.baseVal + return getRotationAngleFromTransformList(tlist, toRad) +} /** * Get the reference element associated with the given attribute value. @@ -1015,8 +1016,8 @@ export let getRotationAngle = function (elem, toRad) { * @returns {Element} Reference element */ export const getRefElem = function (attrVal) { - return getElem(getUrlFromAttr(attrVal).substr(1)); -}; + return getElem(getUrlFromAttr(attrVal).substr(1)) +} /** * Get the reference element associated with the given attribute value. * @function module:utilities.getFeGaussianBlur @@ -1025,18 +1026,18 @@ export const getRefElem = function (attrVal) { */ export const getFeGaussianBlur = function (ele) { if (ele?.firstChild?.tagName === 'feGaussianBlur') { - return ele.firstChild; + return ele.firstChild } else { - const childrens = ele.children; + const childrens = ele.children // eslint-disable-next-line no-unused-vars - for (const [ _, value ] of Object.entries(childrens)) { + for (const [_, value] of Object.entries(childrens)) { if (value.tagName === 'feGaussianBlur') { - return value; + return value } } } - return null; -}; + return null +} /** * Get a DOM element by ID within the SVG root element. @@ -1046,8 +1047,8 @@ export const getFeGaussianBlur = function (ele) { */ export const getElem = (id) => { // querySelector lookup - return svgroot_.querySelector('#' + id); -}; + return svgroot_.querySelector('#' + id) +} /** * Assigns multiple attributes to an element. @@ -1059,27 +1060,27 @@ export const getElem = (id) => { * @returns {void} */ export const assignAttributes = function (elem, attrs, suspendLength, unitCheck) { - for (const [ key, value ] of Object.entries(attrs)) { + 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); + : key.substr(0, 6) === 'xlink:' ? NS.XLINK : null) if (isNullish(value)) { if (ns) { - elem.removeAttributeNS(ns, key); + elem.removeAttributeNS(ns, key) } else { - elem.removeAttribute(key); + elem.removeAttribute(key) } - continue; + continue } if (ns) { - elem.setAttributeNS(ns, key, value); + elem.setAttributeNS(ns, key, value) } else if (!unitCheck) { - elem.setAttribute(key, value); + elem.setAttribute(key, value) } else { - setUnitAttr(elem, key, value); + setUnitAttr(elem, key, value) } } -}; +} /** * Remove unneeded (default) attributes, making resulting SVG smaller. @@ -1100,20 +1101,20 @@ export const cleanupElement = function (element) { 'stroke-width': 1, rx: 0, ry: 0 - }; + } if (element.nodeName === 'ellipse') { // Ellipse elements require rx and ry attributes - delete defaults.rx; - delete defaults.ry; + delete defaults.rx + delete defaults.ry } - Object.entries(defaults).forEach(([ attr, val ]) => { + Object.entries(defaults).forEach(([attr, val]) => { if (element.getAttribute(attr) === String(val)) { - element.removeAttribute(attr); + element.removeAttribute(attr) } - }); -}; + }) +} /** * Round value to for snapping. @@ -1122,14 +1123,14 @@ export const cleanupElement = function (element) { * @returns {Integer} */ export const snapToGrid = function (value) { - const unit = svgCanvas.getBaseUnit(); - let stepSize = svgCanvas.getSnappingStep(); + const unit = svgCanvas.getBaseUnit() + let stepSize = svgCanvas.getSnappingStep() if (unit !== 'px') { - stepSize *= getTypeMap()[unit]; + stepSize *= getTypeMap()[unit] } - value = Math.round(value / stepSize) * stepSize; - return value; -}; + value = Math.round(value / stepSize) * stepSize + return value +} /** * Prevents default browser click behaviour on the given element. @@ -1139,9 +1140,9 @@ export const snapToGrid = function (value) { */ export const preventClickDefault = function (img) { img.addEventListener('click', function (e) { - e.preventDefault(); - }); -}; + e.preventDefault() + }) +} /** * @callback module:utilities.GetNextID @@ -1154,8 +1155,8 @@ export const preventClickDefault = function (img) { * @returns {boolean} */ export const isNullish = (val) => { - return val === null || val === undefined; -}; + return val === null || val === undefined +} /** * Overwrite methods for unit testing. @@ -1169,28 +1170,28 @@ export const isNullish = (val) => { export const mock = ({ getHref: getHrefUser, setHref: setHrefUser, getRotationAngle: getRotationAngleUser }) => { - getHref = getHrefUser; - setHref = setHrefUser; - getRotationAngle = getRotationAngleUser; -}; + getHref = getHrefUser + setHref = setHrefUser + getRotationAngle = getRotationAngleUser +} export const stringToHTML = (str) => { - const parser = new DOMParser(); - const doc = parser.parseFromString(str, 'text/html'); - return doc.body.firstChild; -}; + const parser = new DOMParser() + const doc = parser.parseFromString(str, 'text/html') + return doc.body.firstChild +} -export const insertChildAtIndex = function(parent, child, index) { - const doc = stringToHTML(child); - if (!index) index = 0; +export const insertChildAtIndex = function (parent, child, index) { + const doc = stringToHTML(child) + if (!index) index = 0 if (index >= parent.children.length) { - parent.appendChild(doc); + parent.appendChild(doc) } else { - parent.insertBefore(doc, parent.children[index]); + parent.insertBefore(doc, parent.children[index]) } -}; +} // shortcuts to common DOM functions -export const $id = (id) => document.getElementById(id); -export const $qq = (sel) => document.querySelector(sel); -export const $qa = (sel) => [ ...document.querySelectorAll(sel) ]; +export const $id = (id) => document.getElementById(id) +export const $qq = (sel) => document.querySelector(sel) +export const $qa = (sel) => [...document.querySelectorAll(sel)] diff --git a/web-dev-server.config.mjs b/web-dev-server.config.mjs index 10de26a1..d1c6a1eb 100644 --- a/web-dev-server.config.mjs +++ b/web-dev-server.config.mjs @@ -1,12 +1,12 @@ // eslint-disable-next-line node/no-unpublished-import -import { fromRollup } from '@web/dev-server-rollup'; +import { fromRollup } from '@web/dev-server-rollup' // eslint-disable-next-line node/no-unpublished-import -import rollupCommonjs from '@rollup/plugin-commonjs'; +import rollupCommonjs from '@rollup/plugin-commonjs' // eslint-disable-next-line node/no-unpublished-import -import rollupHtml from 'rollup-plugin-html'; +import rollupHtml from 'rollup-plugin-html' -const commonjs = fromRollup(rollupCommonjs); -const html = fromRollup(rollupHtml); +const commonjs = fromRollup(rollupCommonjs) +const html = fromRollup(rollupHtml) export default { mimeTypes: { @@ -21,16 +21,18 @@ export default { 'instrumented/editor/extensions/*/*.html': 'js' }, plugins: [ - html({ include: [ - 'src/editor/panels/*.html', - 'src/editor/templates/*.html', - 'src/editor/dialogs/*.html', - 'src/editor/extensions/*/*.html', - 'instrumented/editor/panels/*.html', - 'instrumented/editor/templates/*.html', - 'instrumented/editor/dialogs/*.html', - 'instrumented/editor/extensions/*/*.html' - ] }), + html({ + include: [ + 'src/editor/panels/*.html', + 'src/editor/templates/*.html', + 'src/editor/dialogs/*.html', + 'src/editor/extensions/*/*.html', + 'instrumented/editor/panels/*.html', + 'instrumented/editor/templates/*.html', + 'instrumented/editor/dialogs/*.html', + 'instrumented/editor/extensions/*/*.html' + ] + }), commonjs({ // explicitely list packages to increase performance include: [ @@ -44,4 +46,4 @@ export default { ] }) ] -}; +}