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 66ca2db9..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,94 +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 - } - }, - { - 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 74afe2fc..b3fd8eec 100644 --- a/.npmignore +++ b/.npmignore @@ -1,19 +1,5 @@ -ignore -screencasts - -.github/ISSUE_TEMPLATE/bug_report.md -gh-disabled-workflows -build lgtm.yml - -cypress/** -cypress.env.json - coverage/** .nyc_output instrumented/** - -releases - -tools -.eslintcache +node_modules/** diff --git a/.remarkrc b/.remarkrc deleted file mode 100644 index da24a20e..00000000 --- a/.remarkrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "plugins": { - "lint-ordered-list-marker-value": "one" - } -} diff --git a/AUTHORS b/AUTHORS index 28d0ba8b..873359f0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,6 +4,7 @@ Jeff Schiller Vidar Hokstad Alexis Deveria Brett Zamir +Optimistik SAS Translation credits: diff --git a/CHANGES.md b/CHANGES.md index 72ace049..e4ae358d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,11 +1,20 @@ # SVG-Edit CHANGES - -## 7.0.0 (preview - work in progress) +## 7.1.1 +- Fix an issue when moving a text with an existing transformation (issue #689) +## 7.1.0 +- Large refactoring of svgcanvas (a lot of remaining work with the goal to separate in its own package).This explains the move to a minor version +- move to a new linter (standard). +- Several issues fixed +## 7.0.2 +- create an IIFE build. +## 7.0.1 +- remove ext-overview in default extensions for performance reasons +## 7.0.0 - New UI - Rearchitecture the code (more modular) -- simplify and refresh the build process +- Simplify and refresh the build process - Introduce Web Component to replace jQuery UI -- update dependencies +- Update dependencies ## 6.0.0 (unreleased) - Project: Add `FUNDING.yml` to accept contributions diff --git a/README.md b/README.md index fa70415c..6bff697c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# SVG-Edit +# SVGEdit [![npm](https://img.shields.io/npm/v/svgedit.svg)](https://www.npmjs.com/package/svgedit) [![Dependencies](https://img.shields.io/david/SVG-Edit/svgedit.svg)](https://david-dm.org/SVG-Edit/svgedit) @@ -24,19 +24,25 @@ works in any modern browser. ![screenshot](docs/screenshot.png) [](https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg) -## Help wanted +## Contributions -SVG-Edit is the most popular open source SVG editor. It was started more than 10 years ago by a fantastic team of developers. Unfortunately, the product was not maintained for a quite long period. We decided to give this tool a new life by refreshing many aspects. -If you can help us to maintain SVG-Edit, you are more than welcome! +SVGEdit is the most popular open source SVG editor. It was started more than 10 years ago by a fantastic team of developers. Unfortunately, the product was not maintained for a quite long period. We decided to give this tool a new life by refreshing many aspects. +Please let us know with an issue or a discussions if you wish to contribute. ## Demo -Thanks to Netlify, you can test the following builds: +Thanks to **Netlify**, you can test the following builds: -### [Try SVG-edit V7-preview here](https://svgedit.netlify.app/editor/index.html) +### [Try SVGEdit 7.1.x here](https://svgedit.netlify.app/editor/index.html) -[Try SVG-edit 5.1.0 here](https://6098683962bf91702907ee33--svgedit.netlify.app/editor/svg-editor.html) +[Try SVGEdit 5.1.0 here](https://6098683962bf91702907ee33--svgedit.netlify.app/editor/svg-editor.html) -[Try SVG-edit 6.1.0 here](https://60a0000fc9900b0008fd268d--svgedit.netlify.app/editor/index.html) +[Try SVGEdit 6.1.0 here](https://60a0000fc9900b0008fd268d--svgedit.netlify.app/editor/index.html) + +Additional tip: you may try a version released on NPM using unpkg for example with version 7.1.0: +[https://unpkg.com/svgedit@7.1.0/dist/editor/index.html](https://unpkg.com/svgedit@7.1.0/dist/editor/index.html) + +Prior V7 for example with version 3.2.0: +[https://unpkg.com/svgedit@3.2.0/editor/svg-editor.html](https://unpkg.com/svgedit@3.2.0/editor/svg-editor.html) ## Installation @@ -47,33 +53,20 @@ Thanks to Netlify, you can test the following builds: 1. run `npm run start` to start a local server 1. Use your browser to access `http://localhost:8000/src/editor/index.html` -### Integrating SVG-edit into your own application +### Integrating SVGEdit into your own application -V7 is changing significantly the way to integrate and customize SVG-Edit. The documentation will be detailed here. +V7 is changing significantly the way to integrate and customize SVG-Edit. You can have a look to index.html to see how you can insert a div element into your HTML code and inject the editor into the div. SVG-Edit is made of two major components: 1. The "svgcanvas" that takes care of the underlying svg edition. It can be used to build your own editor. See example in the demos folder or the svg-edit-react repository. 1. The "editor" that takes care of the editor UI (menus, buttons, etc.) -For earlier versions of SVG-Edit, please look in their respective branches. +For earlier versions of SVGEdit, please look in their respective branches. ## Supported browsers - - - Opera 59+, - - Chrome 75+, - - FireFox 68+, - - Safari 11+ - - Edge 18+ - - Support for old browsers may require to use an older version of the package. However, - please open an issue if you need support for a specific version of your browser so - the project team can decide if we should support with the latest version. - + Developments and Continuous Integration are done with a **Chrome** environment. Chrome, FireFox and Safari recent versions are supported (in the meaning that we will try to fix bugs for these browsers). + Support for old browsers may require to use an older version of the package. However, please open an issue if you need support for a specific version of your browser so the project team can decide if we should support with the latest version. ## Further reading and more information * Participate in [discussions](https://github.com/SVG-Edit/svgedit/discussions) - * See [docs](docs/) for more documentation. See the - [JSDocs for our latest release](https://svg-edit.github.io/svgedit/releases/latest/docs/jsdoc/index.html). - * [Acknowledgements](docs/Acknowledgements.md) lists open source projects - used in svg-edit. * See [AUTHORS](AUTHORS) file for authors. * [StackOverflow](https://stackoverflow.com/tags/svg-edit) group. diff --git a/src/editor/extensions/ext-connector/ext-connector.js b/archive/untested-extensions/ext-connector/ext-connector.js similarity index 99% rename from src/editor/extensions/ext-connector/ext-connector.js rename to archive/untested-extensions/ext-connector/ext-connector.js index ebd3394a..ad8fabfb 100644 --- a/src/editor/extensions/ext-connector/ext-connector.js +++ b/archive/untested-extensions/ext-connector/ext-connector.js @@ -31,7 +31,6 @@ export default { const { svgCanvas } = svgEditor; const { getElem, $id, mergeDeep } = svgCanvas; const { svgroot } = S; - const { imgPath } = svgEditor.configObj.curConfig; const addElem = svgCanvas.addSVGElementFromJson; const selManager = S.selectorManager; await loadExtensionTranslation(svgEditor); @@ -354,10 +353,10 @@ export default { return { name: svgEditor.i18next.t(`${name}:name`), callback() { - const btitle = svgEditor.i18next.t(`${name}:langListTitle`); + const btitle = `${name}:langListTitle`; // eslint-disable-next-line no-unsanitized/property const buttonTemplate = ` - + `; svgCanvas.insertChildAtIndex($id('tools_left'), buttonTemplate, 13); $id('mode_connect').addEventListener("click", () => { diff --git a/src/editor/extensions/ext-connector/locale/en.js b/archive/untested-extensions/ext-connector/locale/en.js similarity index 100% rename from src/editor/extensions/ext-connector/locale/en.js rename to archive/untested-extensions/ext-connector/locale/en.js diff --git a/src/editor/extensions/ext-connector/locale/fr.js b/archive/untested-extensions/ext-connector/locale/fr.js similarity index 100% rename from src/editor/extensions/ext-connector/locale/fr.js rename to archive/untested-extensions/ext-connector/locale/fr.js diff --git a/src/editor/extensions/ext-connector/locale/zh-CN.js b/archive/untested-extensions/ext-connector/locale/zh-CN.js similarity index 100% rename from src/editor/extensions/ext-connector/locale/zh-CN.js rename to archive/untested-extensions/ext-connector/locale/zh-CN.js diff --git a/archive/untested-extensions/ext-markers/ext-markers.js b/archive/untested-extensions/ext-markers/ext-markers.js deleted file mode 100644 index cb324f44..00000000 --- a/archive/untested-extensions/ext-markers/ext-markers.js +++ /dev/null @@ -1,623 +0,0 @@ -/** - * @file ext-markers.js - * - * @license Apache-2.0 - * - * @copyright 2010 Will Schleter based on ext-arrows.js by Copyright(c) 2010 Alexis Deveria - * - * This extension provides for the addition of markers to the either end - * or the middle of a line, polyline, path, polygon. - * - * Markers may be either a graphic or arbitary text - * - * to simplify the coding and make the implementation as robust as possible, - * markers are not shared - every object has its own set of markers. - * this relationship is maintained by a naming convention between the - * ids of the markers and the ids of the object - * - * The following restrictions exist for simplicty of use and programming - * objects and their markers to have the same color - * marker size is fixed - * text marker font, size, and attributes are fixed - * an application specific attribute - se_type - is added to each marker element - * to store the type of marker - * - * @todo - * remove some of the restrictions above - * add option for keeping text aligned to horizontal - * add support for dimension extension lines - * -*/ - -const loadExtensionTranslation = async function (lang) { - let translationModule; - try { - // eslint-disable-next-line no-unsanitized/method - translationModule = await import(`./locale/${encodeURIComponent(lang)}.js`); - } catch (_error) { - // eslint-disable-next-line no-console - console.error(`Missing translation (${lang}) - using 'en'`); - translationModule = await import(`./locale/en.js`); - } - return translationModule.default; -}; - -export default { - name: 'markers', - async init (S) { - const svgEditor = this; - const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang')); - const { $ } = S; - const { svgCanvas } = svgEditor; - const { $id } = svgCanvas; - const // {svgcontent} = S, - addElem = svgCanvas.addSVGElementFromJson; - const mtypes = [ 'start', 'mid', 'end' ]; - const markerPrefix = 'se_marker_'; - const idPrefix = 'mkr_'; - - // note - to add additional marker types add them below with a unique id - // and add the associated icon(s) to marker-icons.svg - // the geometry is normalized to a 100x100 box with the origin at lower left - // Safari did not like negative values for low left of viewBox - // remember that the coordinate system has +y downward - const markerTypes = { - nomarker: {}, - leftarrow: - { element: 'path', attr: { d: 'M0,50 L100,90 L70,50 L100,10 Z' } }, - rightarrow: - { element: 'path', attr: { d: 'M100,50 L0,90 L30,50 L0,10 Z' } }, - textmarker: - { element: 'text', attr: { - x: 0, y: 0, 'stroke-width': 0, stroke: 'none', - 'font-size': 75, 'font-family': 'serif', 'text-anchor': 'left', - 'xml:space': 'preserve' - } }, - forwardslash: - { element: 'path', attr: { d: 'M30,100 L70,0' } }, - reverseslash: - { element: 'path', attr: { d: 'M30,0 L70,100' } }, - verticalslash: - { element: 'path', attr: { d: 'M50,0 L50,100' } }, - box: - { element: 'path', attr: { d: 'M20,20 L20,80 L80,80 L80,20 Z' } }, - star: - { element: 'path', attr: { d: 'M10,30 L90,30 L20,90 L50,10 L80,90 Z' } }, - xmark: - { element: 'path', attr: { d: 'M20,80 L80,20 M80,80 L20,20' } }, - triangle: - { element: 'path', attr: { d: 'M10,80 L50,20 L80,80 Z' } }, - mcircle: - { element: 'circle', attr: { r: 30, cx: 50, cy: 50 } } - }; - - // duplicate shapes to support unfilled (open) marker types with an _o suffix - [ 'leftarrow', 'rightarrow', 'box', 'star', 'mcircle', 'triangle' ].forEach((v) => { - markerTypes[v + '_o'] = markerTypes[v]; - }); - - /** - * @param {Element} elem - A graphic element will have an attribute like marker-start - * @param {"marker-start"|"marker-mid"|"marker-end"} attr - * @returns {Element} The marker element that is linked to the graphic element - */ - function getLinked (elem, attr) { - const str = elem.getAttribute(attr); - if (!str) { return null; } - const m = str.match(/\(#(.*)\)/); - // const m = str.match(/\(#(?.+)\)/); - // if (!m || !m.groups.id) { - if (!m || m.length !== 2) { - return null; - } - return svgCanvas.getElem(m[1]); - // return svgCanvas.getElem(m.groups.id); - } - - /** - * - * @param {"start"|"mid"|"end"} pos - * @param {string} id - * @returns {void} - */ - function setIcon (pos, id) { - if (id.substr(0, 1) !== '\\') { id = '\\textmarker'; } - const ci = idPrefix + pos + '_' + id.substr(1); - svgEditor.setIcon('cur_' + pos + '_marker_list', $id(ci).children); - $id(ci).classList.add('current'); - const siblings = Array.prototype.filter.call($id(ci).parentNode.children, function(child){ - return child !== $id(ci); - }); - Array.from(siblings).forEach(function(sibling) { - sibling.classList.remove('current'); - }); - } - - let selElems; - /** - * Toggles context tool panel off/on. Sets the controls with the - * selected element's settings. - * @param {boolean} on - * @returns {void} - */ - function showPanel (on) { - $id('marker_panel').style.display = (on) ? 'block' : 'none'; - - if (on) { - const el = selElems[0]; - - let val; let ci; - $.each(mtypes, function (i, pos) { - const m = getLinked(el, 'marker-' + pos); - const txtbox = $id(pos + '_marker'); - if (!m) { - val = '\\nomarker'; - ci = val; - txtbox.style.display = 'none'; - } else { - if (!m.attributes.se_type) { return; } // not created by this extension - val = '\\' + m.attributes.se_type.textContent; - ci = val; - if (val === '\\textmarker') { - val = m.lastChild.textContent; - // txtbox.show(); // show text box - } else { - txtbox.style.display = 'none'; - } - } - txtbox.value = val; - setIcon(pos, ci); - }); - } - } - - /** - * @param {string} id - * @param {""|"\\nomarker"|"nomarker"|"leftarrow"|"rightarrow"|"textmarker"|"forwardslash"|"reverseslash"|"verticalslash"|"box"|"star"|"xmark"|"triangle"|"mcircle"} val - * @returns {SVGMarkerElement} - */ - function addMarker (id, val) { - const txtBoxBg = '#ffffff'; - const txtBoxBorder = 'none'; - const txtBoxStrokeWidth = 0; - - let marker = svgCanvas.getElem(id); - if (marker) { return undefined; } - - if (val === '' || val === '\\nomarker') { return undefined; } - - const el = selElems[0]; - const color = el.getAttribute('stroke'); - // NOTE: Safari didn't like a negative value in viewBox - // so we use a standardized 0 0 100 100 - // with 50 50 being mapped to the marker position - const strokeWidth = 10; - let refX = 50; - let refY = 50; - let viewBox = '0 0 100 100'; - let markerWidth = 5; - let markerHeight = 5; - const seType = (val.substr(0, 1) === '\\') ? val.substr(1) : 'textmarker'; - - if (!markerTypes[seType]) { return undefined; } // an unknown type! - - // create a generic marker - marker = addElem({ - element: 'marker', - attr: { - id, - markerUnits: 'strokeWidth', - orient: 'auto', - style: 'pointer-events:none', - se_type: seType - } - }); - - if (seType !== 'textmarker') { - const mel = addElem(markerTypes[seType]); - const fillcolor = (seType.substr(-2) === '_o') - ? 'none' - : color; - - mel.setAttribute('fill', fillcolor); - mel.setAttribute('stroke', color); - mel.setAttribute('stroke-width', strokeWidth); - marker.append(mel); - } else { - const text = addElem(markerTypes[seType]); - // have to add text to get bounding box - text.textContent = val; - const tb = text.getBBox(); - // alert(tb.x + ' ' + tb.y + ' ' + tb.width + ' ' + tb.height); - const pad = 1; - const bb = tb; - bb.x = 0; - bb.y = 0; - bb.width += pad * 2; - bb.height += pad * 2; - // shift text according to its size - text.setAttribute('x', pad); - text.setAttribute('y', bb.height - pad - tb.height / 4); // kludge? - text.setAttribute('fill', color); - refX = bb.width / 2 + pad; - refY = bb.height / 2 + pad; - viewBox = bb.x + ' ' + bb.y + ' ' + bb.width + ' ' + bb.height; - markerWidth = bb.width / 10; - markerHeight = bb.height / 10; - - const box = addElem({ - element: 'rect', - attr: { - x: bb.x, - y: bb.y, - width: bb.width, - height: bb.height, - fill: txtBoxBg, - stroke: txtBoxBorder, - 'stroke-width': txtBoxStrokeWidth - } - }); - marker.setAttribute('orient', 0); - marker.append(box, text); - } - - marker.setAttribute('viewBox', viewBox); - marker.setAttribute('markerWidth', markerWidth); - marker.setAttribute('markerHeight', markerHeight); - marker.setAttribute('refX', refX); - marker.setAttribute('refY', refY); - svgCanvas.findDefs().append(marker); - - return marker; - } - - /** - * @param {Element} elem - * @returns {SVGPolylineElement} - */ - function convertline (elem) { - // this routine came from the connectors extension - // it is needed because midpoint markers don't work with line elements - if (elem.tagName !== 'line') { return elem; } - - // Convert to polyline to accept mid-arrow - - const x1 = Number(elem.getAttribute('x1')); - const x2 = Number(elem.getAttribute('x2')); - const y1 = Number(elem.getAttribute('y1')); - const y2 = Number(elem.getAttribute('y2')); - const { id } = elem; - - const midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' '); - const pline = addElem({ - element: 'polyline', - attr: { - points: (x1 + ',' + y1 + midPt + x2 + ',' + y2), - stroke: elem.getAttribute('stroke'), - 'stroke-width': elem.getAttribute('stroke-width'), - fill: 'none', - opacity: elem.getAttribute('opacity') || 1 - } - }); - $.each(mtypes, function (i, pos) { // get any existing marker definitions - const nam = 'marker-' + pos; - const m = elem.getAttribute(nam); - if (m) { pline.setAttribute(nam, elem.getAttribute(nam)); } - }); - - const batchCmd = new S.BatchCommand(); - batchCmd.addSubCommand(new S.RemoveElementCommand(elem, elem.parentNode)); - batchCmd.addSubCommand(new S.InsertElementCommand(pline)); - - elem.insertAdjacentElement('afterend', pline); - elem.remove(); - svgCanvas.clearSelection(); - pline.id = id; - svgCanvas.addToSelection([ pline ]); - S.addCommandToHistory(batchCmd); - return pline; - } - - /** - * - * @returns {void} - */ - function setMarker () { - const poslist = { start_marker: 'start', mid_marker: 'mid', end_marker: 'end' }; - const pos = poslist[this.id]; - const markerName = 'marker-' + pos; - const el = selElems[0]; - const marker = getLinked(el, markerName); - if (marker) { marker.remove(); } - el.removeAttribute(markerName); - let val = this.value; - if (val === '') { val = '\\nomarker'; } - if (val === '\\nomarker') { - setIcon(pos, val); - svgCanvas.call('changed', selElems); - return; - } - // Set marker on element - const id = markerPrefix + pos + '_' + el.id; - addMarker(id, val); - svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')'); - if (el.tagName === 'line' && pos === 'mid') { - convertline(el); - } - svgCanvas.call('changed', selElems); - setIcon(pos, val); - } - - /** - * Called when the main system modifies an object. This routine changes - * the associated markers to be the same color. - * @param {Element} elem - * @returns {void} - */ - function colorChanged (elem) { - const color = elem.getAttribute('stroke'); - - $.each(mtypes, function (i, pos) { - const marker = getLinked(elem, 'marker-' + pos); - if (!marker) { return; } - if (!marker.attributes.se_type) { return; } // not created by this extension - const ch = marker.lastElementChild; - if (!ch) { return; } - const curfill = ch.getAttribute('fill'); - const curstroke = ch.getAttribute('stroke'); - if (curfill && curfill !== 'none') { ch.setAttribute('fill', color); } - if (curstroke && curstroke !== 'none') { ch.setAttribute('stroke', color); } - }); - } - - /** - * Called when the main system creates or modifies an object. - * Its primary purpose is to create new markers for cloned objects. - * @param {Element} el - * @returns {void} - */ - function updateReferences (el) { - $.each(mtypes, function (i, pos) { - const id = markerPrefix + pos + '_' + el.id; - const markerName = 'marker-' + pos; - const marker = getLinked(el, markerName); - if (!marker || !marker.attributes.se_type) { return; } // not created by this extension - const url = el.getAttribute(markerName); - if (url) { - const len = el.id.length; - const linkid = url.substr(-len - 1, len); - if (el.id !== linkid) { - const val = $id(pos + '_marker').getAttribute('value'); - addMarker(id, val); - svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')'); - if (el.tagName === 'line' && pos === 'mid') { el = convertline(el); } - svgCanvas.call('changed', selElems); - } - } - }); - } - - // simulate a change event a text box that stores the current element's marker type - /** - * @param {"start"|"mid"|"end"} pos - * @param {string} val - * @returns {void} - */ - function triggerTextEntry (pos, val) { - $id(pos + '_marker').value = val; - $id(pos + '_marker').change(); - } - - /** - * @param {"start"|"mid"|"end"} pos - * @returns {void} Resolves to `undefined` - */ - function showTextPrompt (pos) { - let def = $id(pos + '_marker').value; - if (def.substr(0, 1) === '\\') { def = ''; } - // eslint-disable-next-line no-alert - const txt = prompt('Enter text for ' + pos + ' marker', def); - if (txt) { - triggerTextEntry(pos, txt); - } - } - - /* - function setMarkerSet(obj) { - const parts = this.id.split('_'); - const set = parts[2]; - switch (set) { - case 'off': - triggerTextEntry('start','\\nomarker'); - triggerTextEntry('mid','\\nomarker'); - triggerTextEntry('end','\\nomarker'); - break; - case 'dimension': - triggerTextEntry('start','\\leftarrow'); - triggerTextEntry('end','\\rightarrow'); - await showTextPrompt('mid'); - break; - case 'label': - triggerTextEntry('mid','\\nomarker'); - triggerTextEntry('end','\\rightarrow'); - await showTextPrompt('start'); - break; - } - } - */ - - // callback function for a toolbar button click - /** - * @param {Event} ev - * @returns {Promise} Resolves to `undefined` - */ - async function setArrowFromButton () { - const parts = this.id.split('_'); - const pos = parts[1]; - let val = parts[2]; - if (parts[3]) { val += '_' + parts[3]; } - - if (val !== 'textmarker') { - triggerTextEntry(pos, '\\' + val); - } else { - await showTextPrompt(pos); - } - } - - /** - * @param {"nomarker"|"leftarrow"|"rightarrow"|"textmarker"|"forwardslash"|"reverseslash"|"verticalslash"|"box"|"star"|"xmark"|"triangle"|"mcircle"} id - * @returns {string} - */ - function getTitle (id) { - const { langList } = strings; - const item = langList.find((itm) => { - return itm.id === id; - }); - return item ? item.title : id; - } - - /** - * Build the toolbar button array from the marker definitions. - * @returns {module:SVGEditor.Button[]} - */ - function buildButtonList () { - const buttons = []; - // const i = 0; - /* - buttons.push({ - id: idPrefix + 'markers_off', - title: 'Turn off all markers', - type: 'context', - events: { click: setMarkerSet }, - panel: 'marker_panel' - }); - buttons.push({ - id: idPrefix + 'markers_dimension', - title: 'Dimension', - type: 'context', - events: { click: setMarkerSet }, - panel: 'marker_panel' - }); - buttons.push({ - id: idPrefix + 'markers_label', - title: 'Label', - type: 'context', - events: { click: setMarkerSet }, - panel: 'marker_panel' - }); - */ - $.each(mtypes, function (k, pos) { - const listname = pos + '_marker_list'; - let def = true; - Object.keys(markerTypes).forEach(function (id) { - const title = getTitle(String(id)); - buttons.push({ - id: idPrefix + pos + '_' + id, - svgicon: id, - icon: id + '.svg', - title, - type: 'context', - events: { click: setArrowFromButton }, - panel: 'marker_panel', - list: listname, - isDefault: def - }); - def = false; - }); - }); - return buttons; - } - - const contextTools = [ - { - type: 'input', - panel: 'marker_panel', - id: 'start_marker', - size: 3, - events: { change: setMarker } - }, { - type: 'button-select', - panel: 'marker_panel', - id: 'start_marker_list', - colnum: 3, - events: { change: setArrowFromButton } - }, { - type: 'input', - panel: 'marker_panel', - id: 'mid_marker', - defval: '', - size: 3, - events: { change: setMarker } - }, { - type: 'button-select', - panel: 'marker_panel', - id: 'mid_marker_list', - colnum: 3, - events: { change: setArrowFromButton } - }, { - type: 'input', - panel: 'marker_panel', - id: 'end_marker', - size: 3, - events: { change: setMarker } - }, { - type: 'button-select', - panel: 'marker_panel', - id: 'end_marker_list', - colnum: 3, - events: { change: setArrowFromButton } - } - ]; - - return { - name: strings.name, - svgicons: '', - callback () { - if($id("marker_panel") !== null) { - $id("marker_panel").classList.add('toolset'); - $id("marker_panel").style.display = 'none'; - } - }, - /* async */ addLangData ({ _importLocale, _lang }) { - return { data: strings.langList }; - }, - selectedChanged (opts) { - // Use this to update the current selected elements - selElems = opts.elems; - - const markerElems = [ 'line', 'path', 'polyline', 'polygon' ]; - - let i = selElems.length; - while (i--) { - const elem = selElems[i]; - if (elem && markerElems.includes(elem.tagName)) { - if (opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - }, - - elementChanged (opts) { - const elem = opts.elems[0]; - if (elem && ( - elem.getAttribute('marker-start') || - elem.getAttribute('marker-mid') || - elem.getAttribute('marker-end') - )) { - colorChanged(elem); - updateReferences(elem); - } - // changing_flag = false; // Not apparently in use - }, - buttons: buildButtonList(), - context_tools: strings.contextTools.map((contextTool, i) => { - return Object.assign(contextTools[i], contextTool); - }) - }; - } -}; diff --git a/archive/extensions/ext-opensave/ext-opensave.js b/archive/untested-extensions/extensions/ext-opensave/ext-opensave.js similarity index 100% rename from archive/extensions/ext-opensave/ext-opensave.js rename to archive/untested-extensions/extensions/ext-opensave/ext-opensave.js diff --git a/babel.config.json b/babel.config.json index e5c26b5f..a5a181fc 100644 --- a/babel.config.json +++ b/babel.config.json @@ -3,8 +3,8 @@ [ "@babel/env", { - "useBuiltIns": "usage", - "corejs": "3.6.5" + "useBuiltIns": "entry", + "corejs": "3.19" } ] ] diff --git a/composer.json b/composer.json index f2c968bd..d30c0e6e 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ }, { "name": "Optimistik SAS", - "email": "contact@optimistik.fr" + "email": "contact@optimistik.io" } ], "keywords": [ diff --git a/cypress/integration/ui/__snapshots__/scenario.js.snap b/cypress/integration/ui/__snapshots__/scenario.js.snap index 84f6b010..db0a2bd4 100644 --- a/cypress/integration/ui/__snapshots__/scenario.js.snap +++ b/cypress/integration/ui/__snapshots__/scenario.js.snap @@ -1,934 +1,732 @@ exports[`use various parts of svg-edit > check tool_source #0`] = ` - - Layer 1 - + + + + Layer 1 + + + `; exports[`use various parts of svg-edit > check tool_fhpath #0`] = ` - - - Layer 1 - - + + + + Layer 1 + + + `; exports[`use various parts of svg-edit > check tool_text #0`] = ` - - - Layer 1 - - AB - - - + + + + Layer 1 + + AB + + + + `; exports[`use various parts of svg-edit > check tool_clone #0`] = ` - - - Layer 1 - - AB - - - AB - - - + + + + Layer 1 + + AB + + + AB + + + + `; exports[`use various parts of svg-edit > check tool_italic #0`] = ` - - - Layer 1 - - AB - - - AB - - - + + + + Layer 1 + + AB + + + AB + + + + `; exports[`use various parts of svg-edit > check tool_bold #0`] = ` - - - Layer 1 - - AB - - - AB - - - + + + + Layer 1 + + AB + + + AB + + + + `; exports[`use various parts of svg-edit > check tool_text_change_x_y_coordinate #0`] = ` - - - Layer 1 - - AB - - - AB - - - + + + + Layer 1 + + AB + + + AB + + + + `; exports[`use various parts of svg-edit > check tool_text_change_font_size #0`] = ` - - - Layer 1 - - AB - - - AB - - - + + + + Layer 1 + + AB + + + AB + + + + `; exports[`use various parts of svg-edit > check tool_text_change_stroke_width #0`] = ` - - - Layer 1 - - AB - - - AB - - - + + + + Layer 1 + + AB + + + AB + + + + `; exports[`use various parts of svg-edit > check tool_text_change_stoke_fill_color #0`] = ` - - - Layer 1 - - AB - - - AB - - - -`; - -exports[`use various parts of svg-edit > check tool_text_anchor_start #0`] = ` - - - Layer 1 - - AB - - - AB - - - -`; - -exports[`use various parts of svg-edit > check tool_text_anchor_middle #0`] = ` - - - Layer 1 - - AB - - - AB - - - -`; - -exports[`use various parts of svg-edit > check tool_text_anchor_end #0`] = ` - - - Layer 1 - - AB - - - AB - - - + + + + Layer 1 + + AB + + + AB + + + + `; exports[`use various parts of svg-edit > check tool_text_change_rotation #0`] = ` - - - Layer 1 - - AB - - - AB - - - + + + + Layer 1 + + AB + + + AB + + + + `; exports[`use various parts of svg-edit > check tool_text_change_blur #0`] = ` - - - Layer 1 - - AB - - - AB - - - - - - - - + + + + Layer 1 + + AB + + + AB + + + + + + + + + `; exports[`use various parts of svg-edit > check tool_text_change_opacity #0`] = ` - - - Layer 1 - - AB - - - AB - - - - - - - - + + + + Layer 1 + + AB + + + AB + + + + + + + + + `; exports[`use various parts of svg-edit > check tool_text_align_to_page #0`] = ` - - - Layer 1 - - AB - - - AB - - - - - - - - + + + + Layer 1 + + AB + + + AB + + + + + + + + + `; exports[`use various parts of svg-edit > check tool_text_delete #0`] = ` - - - Layer 1 - - AB - - - - - - - - + + + + Layer 1 + + AB + + + + `; exports[`use various parts of svg-edit > check tool_text_change_font_family #0`] = ` - - - Layer 1 - - AB - - - - - - - - + + + + Layer 1 + + AB + + + + +`; + +exports[`use various parts of svg-edit > check tool_text_decoration_underline #0`] = ` + + + + Layer 1 + + AB + + + + +`; + +exports[`use various parts of svg-edit > check tool_text_decoration_linethrough #0`] = ` + + + + Layer 1 + + AB + + + + +`; + +exports[`use various parts of svg-edit > check tool_text_decoration_overline #0`] = ` + + + + Layer 1 + + AB + + + + `; diff --git a/cypress/integration/ui/__snapshots__/scenario1.js.snap b/cypress/integration/ui/__snapshots__/scenario1.js.snap index 5a8ea21f..da852965 100644 --- a/cypress/integration/ui/__snapshots__/scenario1.js.snap +++ b/cypress/integration/ui/__snapshots__/scenario1.js.snap @@ -1,91 +1,76 @@ exports[`use all parts of svg-edit > check tool_source_set #0`] = ` - - Layer 1 - + + + + Layer 1 + + + `; exports[`use all parts of svg-edit > check tool_shape #0`] = ` - - - Layer 1 - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_image #0`] = ` - - - Layer 1 - - - - - - + + + + Layer 1 + + + + + + + `; diff --git a/cypress/integration/ui/__snapshots__/scenario2.js.snap b/cypress/integration/ui/__snapshots__/scenario2.js.snap index 241be924..61164b81 100644 --- a/cypress/integration/ui/__snapshots__/scenario2.js.snap +++ b/cypress/integration/ui/__snapshots__/scenario2.js.snap @@ -1,717 +1,573 @@ exports[`use all parts of svg-edit > check tool_source_set #0`] = ` - - Layer 1 - + + + + Layer 1 + + + `; exports[`use all parts of svg-edit > check tool_circle #0`] = ` - - - Layer 1 - - - - - + + + + Layer 1 + + + + + + `; exports[`use all parts of svg-edit > check tool_fhellipse #0`] = ` - - - Layer 1 - - - - - - + + + + Layer 1 + + + + + + + `; exports[`use all parts of svg-edit > check tool_ellipse #0`] = ` - - - Layer 1 - - - - - - - + + + + Layer 1 + + + + + + + + `; exports[`use all parts of svg-edit > check tool_circle_change_fill_color #0`] = ` - - - Layer 1 - - - - - + + + + Layer 1 + + + + + + `; exports[`use all parts of svg-edit > check tool_circle_change_opacity #0`] = ` - - - Layer 1 - - - - - + + + + Layer 1 + + + + + + `; exports[`use all parts of svg-edit > check tool_ellipse_change_rotation #0`] = ` - - - Layer 1 - - - - - + + + + Layer 1 + + + + + + `; exports[`use all parts of svg-edit > check tool_ellipse_change_blur #0`] = ` - - - Layer 1 - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_ellipse_change_cx_cy_coordinate #0`] = ` - - - Layer 1 - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_ellipse_change_rx_ry_radius #0`] = ` - - - Layer 1 - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_ellipse_bring_to_back #0`] = ` - - - Layer 1 - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_ellipse_bring_to_front #0`] = ` - - - Layer 1 - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_ellipse_clone #0`] = ` - - - Layer 1 - - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + + `; diff --git a/cypress/integration/ui/__snapshots__/scenario3.js.snap b/cypress/integration/ui/__snapshots__/scenario3.js.snap index 597286a4..8a996817 100644 --- a/cypress/integration/ui/__snapshots__/scenario3.js.snap +++ b/cypress/integration/ui/__snapshots__/scenario3.js.snap @@ -1,158 +1,128 @@ exports[`use all parts of svg-edit > check tool_source_set #0`] = ` - - Layer 1 - + + + + Layer 1 + + + `; exports[`use all parts of svg-edit > check tool_path #0`] = ` - - - Layer 1 - - - - - + + + + Layer 1 + + + + + + `; exports[`use all parts of svg-edit > check tool_path_change_node_xy #0`] = ` - - - Layer 1 - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_path_change_seg_type #0`] = ` - - - Layer 1 - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_path_change_clone_node #0`] = ` - - - Layer 1 - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_path_openclose #0`] = ` - - - Layer 1 - - - + + + + Layer 1 + + + + `; diff --git a/cypress/integration/ui/__snapshots__/scenario4.js.snap b/cypress/integration/ui/__snapshots__/scenario4.js.snap index 57e732f8..10a5d733 100644 --- a/cypress/integration/ui/__snapshots__/scenario4.js.snap +++ b/cypress/integration/ui/__snapshots__/scenario4.js.snap @@ -1,953 +1,771 @@ exports[`use all parts of svg-edit > check tool_source_set #0`] = ` - - Layer 1 - + + + + Layer 1 + + + `; exports[`use all parts of svg-edit > check tool_rect #0`] = ` - - - Layer 1 - - - - - + + + + Layer 1 + + + + + + `; exports[`use all parts of svg-edit > check tool_fhrect #0`] = ` - - - Layer 1 - - - - - - + + + + Layer 1 + + + + + + + `; exports[`use all parts of svg-edit > check tool_square #0`] = ` - - - Layer 1 - - - - - - - + + + + Layer 1 + + + + + + + + `; exports[`use all parts of svg-edit > check tool_rect_change_fill_color #0`] = ` - - - Layer 1 - - - - - + + + + Layer 1 + + + + + + `; exports[`use all parts of svg-edit > check tool_rect_change_rotation #0`] = ` - - - Layer 1 - - - - - + + + + Layer 1 + + + + + + `; exports[`use all parts of svg-edit > check tool_rect_change_blur #0`] = ` - - - Layer 1 - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_rect_change_opacity #0`] = ` - - - Layer 1 - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_fhrect_change_x_y_coordinate #0`] = ` - - - Layer 1 - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_fhrect_change_width_height #0`] = ` - - - Layer 1 - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_square_clone #0`] = ` - - - Layer 1 - - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_square_bring_to_back #0`] = ` - - - Layer 1 - - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_square_bring_to_front #0`] = ` - - - Layer 1 - - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_square_change_corner_radius #0`] = ` - - - Layer 1 - - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_rect_change_to_path #0`] = ` - - - Layer 1 - - - - - - - - - - - + + + + Layer 1 + + + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_rect_delete #0`] = ` - - - Layer 1 - - - - - - - - - + + + + Layer 1 + + + + + `; diff --git a/cypress/integration/ui/__snapshots__/scenario5.js.snap b/cypress/integration/ui/__snapshots__/scenario5.js.snap index 2f0869fa..eec8bfd2 100644 --- a/cypress/integration/ui/__snapshots__/scenario5.js.snap +++ b/cypress/integration/ui/__snapshots__/scenario5.js.snap @@ -1,605 +1,489 @@ exports[`use all parts of svg-edit > check tool_source_set #0`] = ` - - Layer 1 - + + + + Layer 1 + + + `; exports[`use all parts of svg-edit > check tool_line #0`] = ` - - - Layer 1 - - - - - + + + + Layer 1 + + + + + + `; exports[`use all parts of svg-edit > check tool_line_change_rotation #0`] = ` - - - Layer 1 - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_line_change_blur #0`] = ` - - - Layer 1 - - - - - - - - + + + + Layer 1 + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_line_change_opacity #0`] = ` - - - Layer 1 - - - - - - - - + + + + Layer 1 + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_line_delete #0`] = ` - - - Layer 1 - - - - - - - + + + + Layer 1 + + + `; exports[`use all parts of svg-edit > check tool_line_clone #0`] = ` - - - Layer 1 - - - - - - - - - - - - - + + + + Layer 1 + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_line_bring_to_back #0`] = ` - - - Layer 1 - - - - - - - - - - - + + + + Layer 1 + + + + + + + `; exports[`use all parts of svg-edit > check tool_line_bring_to_front #0`] = ` - - - Layer 1 - - - - - - - - - - - + + + + Layer 1 + + + + + + + `; exports[`use all parts of svg-edit > check tool_line_change_x_y_coordinate #0`] = ` - - - Layer 1 - - - - - - - - - - - + + + + Layer 1 + + + + + + + `; exports[`use all parts of svg-edit > check tool_line_change_stroke_width #0`] = ` - - - Layer 1 - - - - - - - - - - - + + + + Layer 1 + + + + + + + `; exports[`use all parts of svg-edit > check tool_line_change_stoke_color #0`] = ` - - - Layer 1 - - - - - - - - - - - + + + + Layer 1 + + + + + + + `; exports[`use all parts of svg-edit > check tool_line_align_to_page #0`] = ` - - - Layer 1 - - - - - - - - - - - + + + + Layer 1 + + + + + + + `; diff --git a/cypress/integration/ui/__snapshots__/scenario6.js.snap b/cypress/integration/ui/__snapshots__/scenario6.js.snap index ab739f1c..df433e92 100644 --- a/cypress/integration/ui/__snapshots__/scenario6.js.snap +++ b/cypress/integration/ui/__snapshots__/scenario6.js.snap @@ -1,605 +1,473 @@ exports[`use all parts of svg-edit > check tool_source_set #0`] = ` - - Layer 1 - + + + + Layer 1 + + + `; exports[`use all parts of svg-edit > check tool_polygon #0`] = ` - - - Layer 1 - - - - - + + + + Layer 1 + + + + + + `; exports[`use all parts of svg-edit > check tool_polygon_clone #0`] = ` - - - Layer 1 - - - - + + + + Layer 1 + + + + + `; exports[`use all parts of svg-edit > check tool_polygon_change_rotation #0`] = ` - - - Layer 1 - - - - + + + + Layer 1 + + + + + `; exports[`use all parts of svg-edit > check tool_polygon_change_blur #0`] = ` - - - Layer 1 - - - - - - - - - + + + + Layer 1 + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_polygon_change_opacity #0`] = ` - - - Layer 1 - - - - - - - - - + + + + Layer 1 + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_polygon_bring_to_back #0`] = ` - - - Layer 1 - - - - - - - - - + + + + Layer 1 + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_polygon_bring_to_front #0`] = ` - - - Layer 1 - - - - - - - - - + + + + Layer 1 + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_polygon_delete #0`] = ` - - - Layer 1 - - - - - - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_polygon_align_to_page #0`] = ` - - - Layer 1 - - - - - - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_polygon_change_stroke_width #0`] = ` - - - Layer 1 - - - - - - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_polygon_change_stoke_fill_color #0`] = ` - - - Layer 1 - - - - - - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_polygon_change_sides #0`] = ` - - - Layer 1 - - - - - - - - + + + + Layer 1 + + + + `; diff --git a/cypress/integration/ui/__snapshots__/scenario7.js.snap b/cypress/integration/ui/__snapshots__/scenario7.js.snap index 8f3a7b28..07217ad4 100644 --- a/cypress/integration/ui/__snapshots__/scenario7.js.snap +++ b/cypress/integration/ui/__snapshots__/scenario7.js.snap @@ -1,659 +1,527 @@ exports[`use all parts of svg-edit > check tool_source_set #0`] = ` - - Layer 1 - + + + + Layer 1 + + + `; exports[`use all parts of svg-edit > check tool_star #0`] = ` - - - Layer 1 - - - - - + + + + Layer 1 + + + + + + `; exports[`use all parts of svg-edit > check tool_star_clone #0`] = ` - - - Layer 1 - - - - + + + + Layer 1 + + + + + `; exports[`use all parts of svg-edit > check tool_star_change_rotation #0`] = ` - - - Layer 1 - - - - + + + + Layer 1 + + + + + `; exports[`use all parts of svg-edit > check tool_star_change_blur #0`] = ` - - - Layer 1 - - - - - - - - - + + + + Layer 1 + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_star_change_opacity #0`] = ` - - - Layer 1 - - - - - - - - - + + + + Layer 1 + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_star_bring_to_back #0`] = ` - - - Layer 1 - - - - - - - - - + + + + Layer 1 + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_star_bring_to_front #0`] = ` - - - Layer 1 - - - - - - - - - + + + + Layer 1 + + + + + + + + + + `; exports[`use all parts of svg-edit > check tool_star_delete #0`] = ` - - - Layer 1 - - - - - - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_star_align_to_page #0`] = ` - - - Layer 1 - - - - - - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_star_change_stroke_width #0`] = ` - - - Layer 1 - - - - - - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_star_change_stoke_fill_color #0`] = ` - - - Layer 1 - - - - - - - - + + + + Layer 1 + + + + `; exports[`use all parts of svg-edit > check tool_star_change_sides #0`] = ` - - - Layer 1 - - - - - - - - + + + + Layer 1 + + + + `; diff --git a/cypress/integration/ui/accessibility.js b/cypress/integration/ui/accessibility.js deleted file mode 100644 index bb383668..00000000 --- a/cypress/integration/ui/accessibility.js +++ /dev/null @@ -1,43 +0,0 @@ -import { - visitAndApproveStorage -} from '../../support/ui-test-helper.js'; - -describe('UI - Accessibility', function () { - beforeEach(() => { - visitAndApproveStorage(); - cy.injectAxe(); - }); - // https://www.npmjs.com/package/cypress-axe - it.skip('Has no detectable a11y violations on load', () => { - // Configure aXe and test the page at initial load - cy.configureAxe({ - // Todo: Reenable when have time to fix - // See https://www.deque.com/axe/axe-for-web/documentation/api-documentation/#user-content-parameters-1 - rules: [ { - id: 'meta-viewport', - enabled: false - } ] - /* - branding: { - brand: String, - application: String - }, - reporter: 'option', - checks: [Object], - rules: [Object], - locale: Object - */ - }); - cy.checkA11y( - {}, - { - rules: { - 'label-title-only': { enabled: false }, - 'page-has-heading-one': { enabled: false }, - region: { enabled: false }, - 'scrollable-region-focusable': { enabled: false } - } - } - ); - }); -}); 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 new file mode 100644 index 00000000..0f4a3694 --- /dev/null +++ b/cypress/integration/ui/issues/issue-660.js @@ -0,0 +1,35 @@ +import { + visitAndApproveStorage +} 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) + }) + /** @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('#svg_source_textarea') + .type('{selectall}', { force: true }) + .type(` + + Layer 1 + hello + + `, { 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 }) + cy.get('#selectorGrip_resize_s') + .trigger('mousedown', { which: 1, force: true }) + .trigger('mousemove', { clientX: 0, clientY: 600 }) + .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) + }) +}) diff --git a/cypress/integration/ui/key-commands.js b/cypress/integration/ui/key-commands.js index 9c00fcc3..f758af70 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'); - }); -}); + it('cmd-A on empty canvas should not cause an error', function () { + cy.get('body').type('{cmd}a') + }) +}) diff --git a/cypress/integration/ui/scenario.js b/cypress/integration/ui/scenario.js index 51424509..bb3f424c 100644 --- a/cypress/integration/ui/scenario.js +++ b/cypress/integration/ui/scenario.js @@ -1,190 +1,184 @@ import { - visitAndApproveStorage -} from '../../support/ui-test-helper.js'; - -const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + visitAndApproveStorage, testSnapshot +} from '../../support/ui-test-helper.js' 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); - it('check tool_text_anchor_start', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#tool_text_anchor_start') - .click({ force: true }); - testSnapshot(); - }); - it('check tool_text_anchor_middle', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#tool_text_anchor_middle') - .click({ force: true }); - testSnapshot(); - }); - it('check tool_text_anchor_end', function () { - cy.get('#svg_1').click({ force: true }); - cy.get('#tool_text_anchor_end') - .click({ force: true }); - testSnapshot(); - }); + .find('#Ok').eq(0).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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened'); - cy.get('#tool_font_family').find('se-list-item').eq(6).shadow().find('elix-option').eq(0) - .click({ force: true }); - cy.get('#svgcontent').toMatchSnapshot(); - }); -}); + cy.get('#svg_1').click({ force: true }) + cy.get('#tool_font_family').shadow().find('select').select('Serif') + testSnapshot() + }) + it('check tool_text_decoration_underline', function () { + cy.get('#svg_1').click({ force: true }) + cy.get('#tool_text_decoration_underline') + .click({ force: true }) + testSnapshot() + }) + it('check tool_text_decoration_linethrough', function () { + cy.get('#svg_1').click({ force: true }) + cy.get('#tool_text_decoration_linethrough') + .click({ force: true }) + testSnapshot() + }) + it('check tool_text_decoration_overline', function () { + cy.get('#svg_1').click({ force: true }) + cy.get('#tool_text_decoration_overline') + .click({ force: true }) + testSnapshot() + }) +}) diff --git a/cypress/integration/ui/scenario1.js b/cypress/integration/ui/scenario1.js index a6567cc0..1ba959fb 100644 --- a/cypress/integration/ui/scenario1.js +++ b/cypress/integration/ui/scenario1.js @@ -1,55 +1,51 @@ import { - visitAndApproveStorage -} from '../../support/ui-test-helper.js'; - -const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + visitAndApproveStorage, testSnapshot +} from '../../support/ui-test-helper.js' 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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'); - }); - cy.get('#svgcontent').toMatchSnapshot(); - }); -}); + 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 c16a71be..26d88ddf 100644 --- a/cypress/integration/ui/scenario2.js +++ b/cypress/integration/ui/scenario2.js @@ -1,124 +1,120 @@ import { - visitAndApproveStorage -} from '../../support/ui-test-helper.js'; - -const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + visitAndApproveStorage, testSnapshot +} from '../../support/ui-test-helper.js' 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + testSnapshot() + }) it('check tool_ellipse_bring_to_back', function () { - cy.get('#svg_2').click({ force: true }); - cy.get('#tool_move_bottom').click({ force: true }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); -}); + 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 ca548f87..fa35b688 100644 --- a/cypress/integration/ui/scenario3.js +++ b/cypress/integration/ui/scenario3.js @@ -1,31 +1,27 @@ import { - visitAndApproveStorage -} from '../../support/ui-test-helper.js'; - -const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + visitAndApproveStorage, testSnapshot +} from '../../support/ui-test-helper.js' 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 +33,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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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').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', { force: true }).should('have.value', '6') cy.get('#ctrlpointgrip_3c1') .trigger('mousedown', { force: true }) .trigger('mousemove', 130, 175, { force: true }) - .trigger('mouseup', { force: true }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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') @@ -95,6 +91,6 @@ describe('use all parts of svg-edit', function () { .trigger('mousedown', 0, 0, { force: true }) .trigger('mouseup', { force: true }); cy.get('#tool_select').click({ force: true }); - cy.get('#svgcontent').toMatchSnapshot(); + testSnapshot(); }); */ -}); +}) diff --git a/cypress/integration/ui/scenario4.js b/cypress/integration/ui/scenario4.js index 36b52d98..c6ad9706 100644 --- a/cypress/integration/ui/scenario4.js +++ b/cypress/integration/ui/scenario4.js @@ -1,164 +1,160 @@ import { - visitAndApproveStorage -} from '../../support/ui-test-helper.js'; - -const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + visitAndApproveStorage, testSnapshot +} from '../../support/ui-test-helper.js' 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + testSnapshot() + }) it('check tool_square_clone', function () { - cy.get('#svg_3').click({ force: true }); - cy.get('#tool_clone').click({ force: true }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + testSnapshot() + }) it('check tool_rect_change_to_path', function () { - cy.get('#svg_2').click({ force: true }); - cy.get('#tool_topath').click({ force: true }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 efa7eb78..3ec70183 100644 --- a/cypress/integration/ui/scenario5.js +++ b/cypress/integration/ui/scenario5.js @@ -1,153 +1,149 @@ import { - visitAndApproveStorage -} from '../../support/ui-test-helper.js'; - -const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + visitAndApproveStorage, testSnapshot +} from '../../support/ui-test-helper.js' 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + testSnapshot() + }) it('check tool_line_delete', function () { - cy.get('#svg_1_id').click({ force: true }); - cy.get('#tool_delete').click({ force: true }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); -}); + .click({ force: true }) + testSnapshot() + }) +}) diff --git a/cypress/integration/ui/scenario6.js b/cypress/integration/ui/scenario6.js index 1f6e749d..53e4c1d9 100644 --- a/cypress/integration/ui/scenario6.js +++ b/cypress/integration/ui/scenario6.js @@ -1,108 +1,104 @@ import { - visitAndApproveStorage -} from '../../support/ui-test-helper.js'; - -const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + visitAndApproveStorage, testSnapshot +} from '../../support/ui-test-helper.js' 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 ++){ @@ -113,38 +109,38 @@ describe('use all parts of svg-edit', function () { cy.get('#selected_y').shadow().find('elix-number-spin-box').eq(0).shadow().find('#upButton').eq(0) .click({ force: true }); } - cy.get('#svgcontent').toMatchSnapshot(); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); -}); + .click({ force: true }) + testSnapshot() + }) +}) diff --git a/cypress/integration/ui/scenario7.js b/cypress/integration/ui/scenario7.js index 5ba4cde1..e5f273eb 100644 --- a/cypress/integration/ui/scenario7.js +++ b/cypress/integration/ui/scenario7.js @@ -1,138 +1,134 @@ import { - visitAndApproveStorage -} from '../../support/ui-test-helper.js'; - -const testSnapshot = () => { - cy.get('#svgcontent').cleanSnapshot(); -}; + visitAndApproveStorage, testSnapshot +} from '../../support/ui-test-helper.js' 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }) } - cy.get('#svgcontent').toMatchSnapshot(); - }); + 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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); + .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 }); - cy.get('#svgcontent').toMatchSnapshot(); - }); -}); + .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 4fa28d76..8b99e700 100644 --- a/cypress/integration/unit/coords.js +++ b/cypress/integration/unit/coords.js @@ -1,26 +1,25 @@ -import { NS } from '../../../instrumented/common/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 - // eslint-disable-next-line no-shadow - 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( @@ -28,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. @@ -54,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 2828ca05..411fa8f2 100644 --- a/cypress/integration/unit/draw.js +++ b/cypress/integration/unit/draw.js @@ -1,30 +1,30 @@ -import { NS } from '../../../instrumented/common/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', - // eslint-disable-next-line max-len d: 'M7.389,57.389C7.389,29.764 29.764,7.389 57.389,7.389C85.013,7.389 107.389,29.764 107.389,57.389C107.389,85.013 85.013,107.389 57.389,107.389C29.764,107.389 7.389,85.013 7.389,57.389z', transform: 'rotate(45 57.388671875000036,57.388671874999986) ', '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 30f4fdca..0c2f943d 100644 --- a/cypress/integration/unit/history.js +++ b/cypress/integration/unit/history.js @@ -1,31 +1,34 @@ -import { NS } from '../../../instrumented/common/namespaces.js'; -import * as utilities from '../../../instrumented/svgcanvas/utilities.js'; -import * as hstory 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 hstory.Command { + 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 []; } // eslint-disable-line class-methods-use-this + + elements () { return [] } } /* @@ -39,479 +42,479 @@ describe('history', function () { * @returns {void} */ beforeEach(function () { - undoMgr = new hstory.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(hstory); - assert.ok(hstory.MoveElementCommand); - assert.ok(hstory.InsertElementCommand); - assert.ok(hstory.ChangeElementCommand); - assert.ok(hstory.RemoveElementCommand); - assert.ok(hstory.BatchCommand); - assert.ok(hstory.UndoManager); - assert.equal(typeof hstory.MoveElementCommand, typeof function () { /* empty fn */ }); - assert.equal(typeof hstory.InsertElementCommand, typeof function () { /* empty fn */ }); - assert.equal(typeof hstory.ChangeElementCommand, typeof function () { /* empty fn */ }); - assert.equal(typeof hstory.RemoveElementCommand, typeof function () { /* empty fn */ }); - assert.equal(typeof hstory.BatchCommand, typeof function () { /* empty fn */ }); - assert.equal(typeof hstory.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 hstory.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 hstory.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 hstory.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 hstory.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 hstory.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 hstory.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 hstory.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'); - let change = new hstory.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 */ }); + 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 */ }) - 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'; - change = new hstory.ChangeElementCommand(this.div1, - { '#text': null }); + this.div1.textContent = 'inner text' + change = new history.ChangeElementCommand(this.div1, + { '#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 = ''; - change = new hstory.ChangeElementCommand(this.div1, - { '#text': 'old text' }); + this.div1.textContent = '' + change = new history.ChangeElementCommand(this.div1, + { '#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'; - change = new hstory.ChangeElementCommand(rect, - { '#href': '#oldhref' }); - assert.equal(justCalled, 'getHref'); + gethrefvalue = '#newhref' + change = new history.ChangeElementCommand(rect, + { '#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 hstory.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 hstory.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 cd033b5c..a0de7a97 100644 --- a/cypress/integration/unit/math.js +++ b/cypress/integration/unit/math.js @@ -1,106 +1,106 @@ -import { NS } from '../../../instrumented/common/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 d6ce68fc..6a61a585 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/common/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; }, - getCurrentZoom () { 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); // eslint-disable-line no-new + const [mockPathContext, mockUtilitiesContext] = getMockContexts() + pathModule.init(mockPathContext) + utilities.init(mockUtilitiesContext) + new Path(path) // eslint-disable-line no-new - 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); // eslint-disable-line no-new + const [mockPathContext, mockUtilitiesContext] = getMockContexts() + pathModule.init(mockPathContext) + utilities.init(mockUtilitiesContext) + new Path(path) // eslint-disable-line no-new - 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); // eslint-disable-line no-new + const [mockPathContext, mockUtilitiesContext] = getMockContexts() + pathModule.init(mockPathContext) + utilities.init(mockUtilitiesContext) + new Path(path) // eslint-disable-line no-new - 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); // eslint-disable-line no-new + const [mockPathContext, mockUtilitiesContext] = getMockContexts() + pathModule.init(mockPathContext) + utilities.init(mockUtilitiesContext) + new Path(path) // eslint-disable-line no-new - 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 195d25c6..c646bb58 100644 --- a/cypress/integration/unit/recalculate.js +++ b/cypress/integration/unit/recalculate.js @@ -1,123 +1,121 @@ -import { NS } from '../../../instrumented/common/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 () { - // eslint-disable-next-line no-shadow - 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) } /** @@ -126,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 12f555da..bb028a2d 100644 --- a/cypress/integration/unit/sanitize.js +++ b/cypress/integration/unit/sanitize.js @@ -1,17 +1,17 @@ -import { NS } from '../../../instrumented/common/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 c839b467..71e88f5c 100644 --- a/cypress/integration/unit/select.js +++ b/cypress/integration/unit/select.js @@ -1,71 +1,72 @@ -import * as select from '../../../instrumented/svgcanvas/select.js'; -import { NS } from '../../../instrumented/common/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} */ - const mockFactory = { + 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 }, - svgRoot () { return svgroot; }, - svgContent () { return svgcontent; }, - getDataStorage () { return dataStorage; } - }; + getSvgRoot () { return svgroot }, + getSvgContent () { return svgContent }, + getDataStorage () { return dataStorage } + } /** * Potentially reusable test set-up. * @returns {void} */ beforeEach(() => { - svgroot = mockFactory.createSVGElement({ + svgroot = mockSvgCanvas.createSVGElement({ element: 'svg', attr: { id: 'svgroot' } - }); - svgcontent = mockFactory.createSVGElement({ + }) + svgContent = mockSvgCanvas.createSVGElement({ element: 'svg', attr: { id: 'svgcontent' } - }); + }) - svgroot.append(svgcontent); - /* const rect = */ svgcontent.append( - mockFactory.createSVGElement({ + svgroot.append(svgContent) + /* const rect = */ svgContent.append( + mockSvgCanvas.createSVGElement({ element: 'rect', attr: { id: 'rect', @@ -75,9 +76,9 @@ describe('select', function () { height: '100' } }) - ); - sandbox.append(svgroot); - }); + ) + sandbox.append(svgroot) + }) /* function setUpWithInit () { @@ -91,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(mockConfig, mockFactory); + 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 a61fdd5a..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-connector.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'); - // ellipses = svgcontent.getElementsByTagNameNS(svgns, 'ellipse'), - 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 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') + // 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') // 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 29cf87c4..b76310c3 100644 --- a/cypress/integration/unit/utilities-bbox.js +++ b/cypress/integration/unit/utilities-bbox.js @@ -1,13 +1,13 @@ -/* eslint-disable max-len */ -import 'pathseg'; +import 'pathseg' -import { NS } from '../../../instrumented/common/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 () { /** @@ -16,439 +16,449 @@ 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 mockaddSVGElementFromJsonCallCount = 0; + let mockaddSVGElementsFromJsonCallCount = 0 /** - * Mock of {@link module:utilities.EditorContext#addSVGElementFromJson}. + * Mock of {@link module:utilities.EditorContext#addSVGElementsFromJson}. * @param {module:utilities.SVGElementJSON} json * @returns {SVGElement} */ - function mockaddSVGElementFromJson (json) { - const elem = mockCreateSVGElement(json); - svgroot.append(elem); - mockaddSVGElementFromJsonCallCount++; - return elem; + function mockaddSVGElementsFromJson (json) { + const elem = mockCreateSVGElement(json) + svgroot.append(elem) + mockaddSVGElementsFromJsonCallCount++ + 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 (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) } - // path.reorientGrads(pth, m); - 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) - path.init(null); - mockaddSVGElementFromJsonCallCount = 0; - }); + 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 + }, + getSvgRoot () { return svgroot } + } + + path.init(mockSvgCanvas) + mockaddSVGElementsFromJsonCallCount = 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, mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 2, height: 2 }); - assert.equal(mockaddSVGElementFromJsonCallCount, 0); - elem.remove(); + }) + svgroot.append(elem) + let bbox = getBBoxWithTransform(elem, mockaddSVGElementsFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 2, height: 2 }) + assert.equal(mockaddSVGElementsFromJsonCallCount, 0) + elem.remove() elem = mockCreateSVGElement({ element: 'rect', attr: { id: 'rect', x: '0', y: '1', width: '5', height: '10' } - }); - svgroot.append(elem); - bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - assert.equal(mockaddSVGElementFromJsonCallCount, 0); - elem.remove(); + }) + svgroot.append(elem) + bbox = getBBoxWithTransform(elem, mockaddSVGElementsFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }) + assert.equal(mockaddSVGElementsFromJsonCallCount, 0) + elem.remove() elem = mockCreateSVGElement({ element: 'line', attr: { id: 'line', x1: '0', y1: '1', x2: '5', y2: '6' } - }); - svgroot.append(elem); - bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }); - assert.equal(mockaddSVGElementFromJsonCallCount, 0); - elem.remove(); + }) + svgroot.append(elem) + bbox = getBBoxWithTransform(elem, mockaddSVGElementsFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }) + assert.equal(mockaddSVGElementsFromJsonCallCount, 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, mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - assert.equal(mockaddSVGElementFromJsonCallCount, 0); - g.remove(); - }); + }) + g.append(elem) + svgroot.append(g) + bbox = getBBoxWithTransform(elem, mockaddSVGElementsFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }) + assert.equal(mockaddSVGElementsFromJsonCallCount, 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, mockaddSVGElementFromJson, 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, mockaddSVGElementsFromJson, 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, mockaddSVGElementFromJson, 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(mockaddSVGElementFromJsonCallCount, 1); - elem.remove(); + }) + svgroot.append(elem) + bbox = getBBoxWithTransform(elem, mockaddSVGElementsFromJson, 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(mockaddSVGElementsFromJsonCallCount, 1) + elem.remove() - const rect = { x: 10, y: 10, width: 10, height: 20 }; - const angle = 45; - const origin = { x: 15, y: 20 }; // eslint-disable-line no-shadow + 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); - mockaddSVGElementFromJsonCallCount = 0; - bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, 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(mockaddSVGElementFromJsonCallCount, 0); - elem.remove(); + }) + svgroot.append(elem) + mockaddSVGElementsFromJsonCallCount = 0 + bbox = getBBoxWithTransform(elem, mockaddSVGElementsFromJson, 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(mockaddSVGElementsFromJsonCallCount, 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); - mockaddSVGElementFromJsonCallCount = 0; - bbox = getBBoxWithTransform(g, mockaddSVGElementFromJson, 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(mockaddSVGElementFromJsonCallCount, 0); - g.remove(); + }) + g.append(elem) + svgroot.append(g) + mockaddSVGElementsFromJsonCallCount = 0 + bbox = getBBoxWithTransform(g, mockaddSVGElementsFromJson, 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(mockaddSVGElementsFromJsonCallCount, 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); - mockaddSVGElementFromJsonCallCount = 0; - bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions); + }) + svgroot.append(elem) + mockaddSVGElementsFromJsonCallCount = 0 + bbox = getBBoxWithTransform(elem, mockaddSVGElementsFromJson, 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(mockaddSVGElementFromJsonCallCount, 1); - elem.remove(); - }); + assert.equal(mockaddSVGElementsFromJsonCallCount, 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, mockaddSVGElementFromJson, 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, mockaddSVGElementsFromJson, 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, mockaddSVGElementFromJson, 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, mockaddSVGElementsFromJson, 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 }; // eslint-disable-line no-shadow - 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, mockaddSVGElementFromJson, 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, mockaddSVGElementsFromJson, 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, mockaddSVGElementFromJson, 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, mockaddSVGElementsFromJson, 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, mockaddSVGElementFromJson, mockPathActions); + }) + svgroot.append(elem) + bbox = getBBoxWithTransform(elem, mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, 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], mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, 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], mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, 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], mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, 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], mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 2, height: 2 }); - elem.remove(); + }) + svgroot.append(elem) + let bbox = getStrokedBBox([elem], mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getStrokedBBox([elem], mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getStrokedBBox([elem], mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - g.remove(); - }); + }) + g.append(elem) + svgroot.append(g) + bbox = getStrokedBBox([elem], mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 2, height: 2 }); - elem.remove(); + }) + svgroot.append(elem) + let bbox = getStrokedBBox([elem], mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getStrokedBBox([elem], mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getStrokedBBox([elem], mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - g.remove(); - }); + }) + g.append(elem) + svgroot.append(g) + bbox = getStrokedBBox([elem], mockaddSVGElementsFromJson, mockPathActions) + assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }) + g.remove() + }) /** * Returns radians for degrees. @@ -456,7 +466,7 @@ describe('utilities bbox', function () { * @returns {Float} */ function radians (degrees) { - return degrees * Math.PI / 180; + return degrees * Math.PI / 180 } /** @@ -466,17 +476,14 @@ describe('utilities bbox', function () { * @param {module:math.XYObject} origin * @returns {module:math.XYObject} */ - function rotatePoint (point, angle, origin) { // eslint-disable-line no-shadow - if (!origin) { - origin = { x: 0, y: 0 }; - } - const x = point.x - origin.x; - const y = point.y - origin.y; - const theta = radians(angle); + function rotatePoint (point, angle, origin = { x: 0, y: 0 }) { + 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 - }; + } } /** * @@ -485,22 +492,22 @@ describe('utilities bbox', function () { * @param {module:math.XYObject} origin * @returns {module:utilities.BBoxObject} */ - function rotateRect (rect, angle, origin) { // eslint-disable-line no-shadow - 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); + 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 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 732f0854..49536cc7 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/common/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,22 +79,22 @@ 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 } /** - * Mock of {@link module:utilities.EditorContext#addSVGElementFromJson}. + * Mock of {@link module:utilities.EditorContext#addSVGElementsFromJson}. * @param {module:utilities.SVGElementJSON} json * @returns {SVGElement} */ - function mockaddSVGElementFromJson (json) { - const elem = mockCreateSVGElement(json); - currentLayer.append(elem); - return elem; + function mockaddSVGElementsFromJson (json) { + const elem = mockCreateSVGElement(json) + currentLayer.append(elem) + return elem } /** @@ -104,50 +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 (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); } - // utilities.reorientGrads(path, m); - return undefined; + return undefined } - }; + } // ////////////////////////////////////////////////////////// // Performance times with various browsers on Macbook 2011 8MB RAM OS X El Capitan 10.11.4 @@ -181,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 ], mockaddSVGElementFromJson, 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], mockaddSVGElementsFromJson, 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 ], mockaddSVGElementFromJson, 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], mockaddSVGElementsFromJson, 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 c30ea97e..4ae3a675 100644 --- a/cypress/integration/unit/utilities.js +++ b/cypress/integration/unit/utilities.js @@ -1,7 +1,5 @@ -/* eslint-disable max-len */ -import * as browser from '../../../instrumented/common/browser.js'; -import * as utilities from '../../../instrumented/svgcanvas/utilities.js'; -import { NS } from '../../../instrumented/common/namespaces.js'; +import * as utilities from '../../../instrumented/svgcanvas/utilities.js' +import { NS } from '../../../instrumented/svgcanvas/namespaces.js' describe('utilities', function () { /** @@ -10,341 +8,335 @@ 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. * @param {module:utilities.SVGElementJSON} json * @returns {SVGElement} */ - function mockaddSVGElementFromJson (json) { - const elem = mockCreateSVGElement(json); - svgroot.append(elem); - return elem; + function mockaddSVGElementsFromJson (json) { + 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 { - // eslint-disable-next-line class-methods-use-this 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; + const mockSvgCanvas = { + addSVGElementsFromJson: mockaddSVGElementsFromJson, + pathActions: mockPathActions, + clearSelection: mockClearSelection, + addToSelection: mockAddToSelection, + history: mockHistory, + addCommandToHistory: mockAddCommandToHistory + } + + 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'); - }); - - it('Test getPathBBox', function () { - if (browser.supportsPathBBox()) { - return; - } - const doc = utilities.text2xml(''); - const path = doc.createElementNS(NS.SVG, 'path'); - path.setAttribute('d', 'm0,0l5,0l0,5l-5,0l0,-5z'); - const bb = utilities.getPathBBox(path); - assert.equal(typeof bb, 'object', 'BBox returned object'); - assert.ok(bb.x && !isNaN(bb.x)); - assert.ok(bb.y && !isNaN(bb.y)); - }); + 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/; - console.log(getPathDFromElement(elem), closeEnough); - 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 () { /** * Wrap `utilities.getBBoxOfElementAsPath` to convert bbox to object for testing. * @type {module:utilities.getBBoxOfElementAsPath} */ - function getBBoxOfElementAsPath (elem, addSVGElementFromJson, pathActions) { - const bbox = utilities.getBBoxOfElementAsPath(elem, addSVGElementFromJson, pathActions); - return utilities.bboxToObj(bbox); // need this for assert.equal() to work. + function getBBoxOfElementAsPath (elem, addSVGElementsFromJson, pathActions) { + const bbox = utilities.getBBoxOfElementAsPath(elem, addSVGElementsFromJson, 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, mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 0, height: 0 }); - elem.remove(); + }) + svgroot.append(elem) + let bbox = getBBoxOfElementAsPath(elem, mockaddSVGElementsFromJson, 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, mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 10 }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getBBoxOfElementAsPath(elem, mockaddSVGElementsFromJson, 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, mockaddSVGElementFromJson, mockPathActions); - assert.deepEqual(bbox, { x: 0, y: 1, width: 5, height: 5 }); - elem.remove(); + }) + svgroot.append(elem) + bbox = getBBoxOfElementAsPath(elem, mockaddSVGElementsFromJson, 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, mockaddSVGElementFromJson, 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, mockSvgCanvas) + 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, mockaddSVGElementFromJson, 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, mockSvgCanvas) + 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 e45867f3..e18b4cd1 100644 --- a/cypress/support/assert-close.js +++ b/cypress/support/assert-close.js @@ -1,5 +1,4 @@ -/* eslint-disable max-len */ -import assertionWrapper from './assertion-wrapper.js'; +import assertionWrapper from './assertion-wrapper.js' /** * @typedef {PlainObject} InfoObject @@ -22,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 } } /** @@ -41,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 } } /** @@ -71,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 } } /** @@ -90,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 } } /** @@ -113,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..ca4d256f 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -23,26 +23,3 @@ // // -- This will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) - -// remove the style attributes that is causing differences in snapshots -const ngAttributes = [ 'style' ]; - -Cypress.Commands.add( - 'cleanSnapshot', - { - prevSubject: true - }, - (subject, _snapshotOptions) => { - let html = subject[0].outerHTML; - - for (const attribute of ngAttributes) { - const expression = new RegExp(`${attribute}[^= ]*="[^"]*"`, 'g'); - html = html.replace(expression, ''); - } - html = html.replace(//g, ''); - - const sanitisedBody = new DOMParser().parseFromString(html, 'text/html').querySelector('body'); - - return cy.wrap(sanitisedBody.firstChild).toMatchSnapshot(); - } -); diff --git a/cypress/support/index.js b/cypress/support/index.js index cf57e23e..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,23 +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'; - -/** - * ACCESSIBILITY. - * @see https://www.npmjs.com/package/cypress-axe - */ -import 'cypress-axe'; +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..ab30e8dc 100644 --- a/cypress/support/ui-test-helper.js +++ b/cypress/support/ui-test-helper.js @@ -1,24 +1,31 @@ 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() +} + +export const testSnapshot = () => { + cy.window().then((win) => { // access to the remote Window so we can get the svgEditor variable + const svgString = win.svgEditor.svgCanvas.getSvgString() + const svgDom = new DOMParser().parseFromString(svgString, 'text/html').querySelector('body') + cy.wrap(svgDom).toMatchSnapshot() + }) +} diff --git a/demos/canvas.html b/demos/canvas.html index b82d1cdf..c98aee3d 100644 --- a/demos/canvas.html +++ b/demos/canvas.html @@ -16,21 +16,25 @@
[ - ] + + ]
- + + diff --git a/docs/jsdoc-config.js b/docs/jsdoc-config.js index 88c78af1..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: { @@ -14,7 +14,6 @@ module.exports = { 'screencasts', 'test' ], - // eslint-disable-next-line max-len excludePattern: 'svgedit-config-*|build-html.js|rollup*|external/babel-polyfill|extensions/mathjax|imagelib/jquery.min.js|jspdf/jspdf.min.js|jspdf/underscore-min.js|jquery-ui|jquery.min.js|js-hotkeys' }, sourceType: 'module', @@ -34,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 53c4f882..4674e50a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,131 +1,112 @@ { "name": "svgedit", - "version": "7.0.0-beta.6", + "version": "7.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "svgedit", - "version": "7.0.0-beta.6", + "version": "7.1.1", "license": "(MIT AND Apache-2.0 AND ISC AND LGPL-3.0-or-later AND X11)", "dependencies": { "@babel/polyfill": "7.12.1", - "browser-fs-access": "^0.20.4", - "canvg": "3.0.7", - "core-js": "3.16.3", - "elix": "15.0.0", - "html2canvas": "1.3.2", - "i18next": "20.4.0", - "jspdf": "2.3.1", + "browser-fs-access": "0.23.0", + "canvg": "3.0.9", + "core-js": "3.20.1", + "elix": "15.0.1", + "html2canvas": "1.3.4", + "i18next": "21.6.4", + "jspdf": "2.5.0", "pathseg": "1.2.1", "regenerator-runtime": "0.13.9", - "rollup-plugin-polyfill-node": "0.7.0", - "svg2pdf.js": "2.1.0" + "rollup-plugin-polyfill-node": "0.8.0", + "svg2pdf.js": "2.2.0" }, "devDependencies": { - "@babel/core": "7.15.0", - "@babel/preset-env": "7.15.0", - "@babel/register": "7.15.3", - "@babel/runtime-corejs3": "7.15.3", - "@cypress/code-coverage": "3.9.10", - "@cypress/fiddle": "1.19.2", - "@fintechstudios/eslint-plugin-chai-as-promised": "3.1.0", + "@babel/core": "7.16.7", + "@babel/preset-env": "7.16.7", + "@babel/register": "7.16.7", + "@babel/runtime-corejs3": "7.16.7", + "@cypress/code-coverage": "3.9.12", + "@cypress/fiddle": "1.19.3", "@rollup/plugin-babel": "5.3.0", - "@rollup/plugin-commonjs": "18.0.0", - "@rollup/plugin-dynamic-import-vars": "1.4.0", - "@rollup/plugin-node-resolve": "13.0.4", - "@rollup/plugin-replace": "3.0.0", + "@rollup/plugin-commonjs": "^18", + "@rollup/plugin-dynamic-import-vars": "1.4.2", + "@rollup/plugin-node-resolve": "13.1.1", + "@rollup/plugin-replace": "3.0.1", "@rollup/plugin-url": "6.1.0", - "@web/dev-server": "0.1.22", - "@web/dev-server-rollup": "0.3.9", - "axe-core": "4.3.3", + "@web/dev-server": "0.1.29", + "@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.16.3", + "core-js-bundle": "3.20.1", "cp-cli": "2.0.0", - "cypress": "8.3.1", - "cypress-axe": "0.13.0", + "cypress": "9.2.0", "cypress-multi-reporters": "1.5.0", "cypress-plugin-snapshots": "1.4.4", - "eslint": "7.32.0", - "eslint-config-standard": "16.0.3", - "eslint-plugin-array-func": "3.1.7", - "eslint-plugin-chai-expect": "2.2.0", - "eslint-plugin-chai-expect-keywords": "2.1.0", - "eslint-plugin-chai-friendly": "0.7.2", - "eslint-plugin-compat": "3.13.0", - "eslint-plugin-cypress": "2.11.3", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-html": "6.1.2", - "eslint-plugin-import": "2.24.2", - "eslint-plugin-jsdoc": "36.0.8", - "eslint-plugin-markdown": "2.2.0", - "eslint-plugin-no-unsanitized": "3.1.5", - "eslint-plugin-no-use-extend-native": "0.5.0", - "eslint-plugin-node": "11.1.0", - "eslint-plugin-promise": "5.1.0", - "eslint-plugin-standard": "4.1.0", "jamilih": "0.54.0", "jsdoc": "3.6.7", "node-static": "0.7.11", "npm-run-all": "4.1.5", "nyc": "15.1.0", - "open-cli": "7.0.0", + "open-cli": "7.0.1", "promise-fs": "2.1.1", "qr-manipulation": "0.7.0", "query-result": "1.0.5", - "remark-cli": "10.0.0", - "remark-lint-ordered-list-marker-value": "3.0.1", + "remark-cli": "10.0.1", + "remark-lint-ordered-list-marker-value": "3.1.1", "rimraf": "3.0.2", - "rollup": "2.56.3", + "rollup": "2.62.0", "rollup-plugin-copy": "3.4.0", "rollup-plugin-filesize": "9.1.1", + "rollup-plugin-html": "^0.2.1", "rollup-plugin-node-polyfills": "0.2.1", "rollup-plugin-progress": "1.1.2", "rollup-plugin-re": "1.0.7", "rollup-plugin-terser": "7.0.2", - "start-server-and-test": "1.13.1" + "standard": "16.0.4", + "start-server-and-test": "1.14.0" }, "engines": { "node": ">=10" } }, "node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "dependencies": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "version": "7.16.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz", + "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz", - "integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz", + "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.0", - "@babel/helper-module-transforms": "^7.15.0", - "@babel/helpers": "^7.14.8", - "@babel/parser": "^7.15.0", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.7", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -169,12 +150,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", - "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.7.tgz", + "integrity": "sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg==", "dev": true, "dependencies": { - "@babel/types": "^7.15.0", + "@babel/types": "^7.16.7", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -183,39 +164,39 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz", - "integrity": "sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz", - "integrity": "sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "dev": true, "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", - "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", "semver": "^6.3.0" }, "engines": { @@ -235,17 +216,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.8.tgz", - "integrity": "sha512-bpYvH8zJBWzeqi1o+co8qOrw+EXzQ/0c74gVmY205AWXy9nifHrOg77y+1zwxX5lXE7Icq4sPlSQ4O2kWBrteQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz", + "integrity": "sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-member-expression-to-functions": "^7.14.7", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -255,12 +237,12 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", - "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.7.tgz", + "integrity": "sha512-fk5A6ymfp+O5+p2yCkXAu5Kyj6v0xh0RBeNcAkYUMDvvAAoxvSKXn+Jb37t/yWFiQVDFK1ELpUTD8/aLhCPu+g==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-annotate-as-pure": "^7.16.7", "regexpu-core": "^4.7.1" }, "engines": { @@ -271,9 +253,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.0.tgz", + "integrity": "sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg==", "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.13.0", @@ -290,9 +272,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider/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" @@ -321,239 +303,252 @@ "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz", - "integrity": "sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ==", + "node_modules/@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", - "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-get-function-arity": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", - "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", - "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", - "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", + "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", "dev": true, "dependencies": { - "@babel/types": "^7.15.0" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", - "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", - "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", + "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.0", - "@babel/helper-simple-access": "^7.14.8", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", - "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "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.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz", - "integrity": "sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.7.tgz", + "integrity": "sha512-C3o117GnP/j/N2OWo+oepeWbFEKRfNaay+F1Eo5Mj3A1SRjyx+qaFhm23nlipub7Cjv2azdUUiDH+VlpdwUFRg==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-wrap-function": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", - "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", "dev": true, "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.15.0", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", - "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", "dev": true, "dependencies": { - "@babel/types": "^7.14.8" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz", - "integrity": "sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", - "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz", - "integrity": "sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.7.tgz", + "integrity": "sha512-7a9sABeVwcunnztZZ7WTgSw6jVYLzM1wua0Z4HIXm9S3/HC96WKQTkFgGEaj5W06SHHihPJ6Le6HzS5cGOQMNw==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.8.tgz", - "integrity": "sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz", + "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==", "dev": true, "dependencies": { - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.8", - "@babel/types": "^7.14.8" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", + "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -562,9 +557,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.0.tgz", - "integrity": "sha512-0v7oNOjr6YT9Z2RAOTv4T9aP+ubfx4Q/OhVtAet7PFDt0t9Oy6Jn+/rfC6b8HJ5zEqrQCiMxJfgtHpmIminmJQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz", + "integrity": "sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -573,15 +568,30 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz", - "integrity": "sha512-ZoJS2XCKPBfTmL122iP6NM9dOg+d4lc9fFk3zxc8iDjvt8Pk4+TlsHSKhIPf6X+L5ORCdBzqMZDjL/WHj7WknQ==", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", + "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", - "@babel/plugin-proposal-optional-chaining": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", + "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -591,13 +601,13 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.9.tgz", - "integrity": "sha512-d1lnh+ZnKrFKwtTYdw320+sQWCTwgkB9fmUhNXRADA4akR6wLjaruSGnIEUjpt9HCOwTr4ynFTKu19b7rFRpmw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.7.tgz", + "integrity": "sha512-TTXBT3A5c11eqRzaC6beO6rlFT3Mo9C2e8eB44tTr52ESXSK2CIc2fOp1ynpAwQA8HhBMho+WXhMHWlAe3xkpw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.7", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -608,13 +618,13 @@ } }, "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz", - "integrity": "sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", + "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -624,13 +634,13 @@ } }, "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.14.5.tgz", - "integrity": "sha512-KBAH5ksEnYHCegqseI5N9skTdxgJdmDoAOc0uXa+4QMYKeZD0w5IARh4FMlTNtaHhbB8v+KzMdTgxMMzsIy6Yg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", + "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -641,12 +651,12 @@ } }, "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz", - "integrity": "sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { @@ -657,12 +667,12 @@ } }, "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz", - "integrity": "sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", + "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -673,12 +683,12 @@ } }, "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz", - "integrity": "sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", + "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -689,12 +699,12 @@ } }, "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz", - "integrity": "sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", + "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -705,12 +715,12 @@ } }, "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz", - "integrity": "sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", + "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -721,12 +731,12 @@ } }, "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz", - "integrity": "sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -737,16 +747,16 @@ } }, "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz", - "integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz", + "integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.14.7", - "@babel/helper-compilation-targets": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/compat-data": "^7.16.4", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.14.5" + "@babel/plugin-transform-parameters": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -756,12 +766,12 @@ } }, "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", - "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -772,13 +782,13 @@ } }, "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz", - "integrity": "sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", + "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { @@ -789,13 +799,13 @@ } }, "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz", - "integrity": "sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.7.tgz", + "integrity": "sha512-7twV3pzhrRxSwHeIvFE6coPgvo+exNDOiGUMg39o2LiLo1Y+4aKpfkcLGcg1UHonzorCt7SNXnoMyCnnIOA8Sw==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -805,14 +815,14 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-62EyfyA3WA0mZiF2e2IV9mc9Ghwxcg8YTu8BS4Wss4Y3PY725OmS9M0qLORbJwLqFtGh+jiE4wAmocK2CTUK2Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", + "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -823,13 +833,13 @@ } }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz", - "integrity": "sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", + "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=4" @@ -905,12 +915,18 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.0.tgz", + "integrity": "sha512-8zv2+xiPHwly31RK4RmnEYY5zziuF3O7W2kIDW+07ewWDh6Oi0dRq8kwvulRkFgt6DB97RlKs5c1y068iPlCUg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { @@ -1010,12 +1026,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", - "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", + "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1025,14 +1041,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", - "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.7.tgz", + "integrity": "sha512-pFEfjnK4DfXCfAlA5I98BYdDJD8NltMzx19gt6DAmfE+2lXRfPUoa0/5SUjT4+TDE1W/rcxU/1lgN55vpAjjdg==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5" + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1042,12 +1058,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz", - "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1057,12 +1073,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.5.tgz", - "integrity": "sha512-LBYm4ZocNgoCqyxMLoOnwpsmQ18HWTQvql64t3GvMUzLQrNoV1BDG0lNftC8QKYERkZgCCT/7J5xWGObGAyHDw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", + "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1072,17 +1088,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.9.tgz", - "integrity": "sha512-NfZpTcxU3foGWbl4wxmZ35mTsYJy8oQocbeIMoDAGGFarAmSQlL+LWMkDx/tj6pNotpbX3rltIA4dprgAPOq5A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", + "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" }, "engines": { @@ -1093,12 +1110,12 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz", - "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", + "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1108,12 +1125,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", - "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", + "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1123,13 +1140,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz", - "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1139,12 +1156,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz", - "integrity": "sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", + "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1154,13 +1171,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", - "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "dev": true, "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1170,12 +1187,12 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz", - "integrity": "sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", + "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1185,13 +1202,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz", - "integrity": "sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1201,12 +1219,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz", - "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", + "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1216,12 +1234,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz", - "integrity": "sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1231,13 +1249,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz", - "integrity": "sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", + "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -1248,14 +1266,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.0.tgz", - "integrity": "sha512-3H/R9s8cXcOGE8kgMlmjYYC9nqr5ELiPkJn4q0mypBrjhYQoc+5/Maq69vV4xRPWnkzZuwJPf5rArxpB/35Cig==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.7.tgz", + "integrity": "sha512-h2RP2kE7He1ZWKyAlanMZrAbdv+Acw1pA8dQZhE025WJZE2z0xzFADAinXA9fxd5bn7JnM+SdOGcndGx1ARs9w==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.15.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-simple-access": "^7.14.8", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -1266,15 +1284,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.14.5.tgz", - "integrity": "sha512-mNMQdvBEE5DcMQaL5LbzXFMANrQjd2W7FPzg34Y4yEz7dBgdaC+9B84dSO+/1Wba98zoDbInctCDo4JGxz1VYA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", + "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", "dev": true, "dependencies": { - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -1285,13 +1303,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz", - "integrity": "sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", + "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1301,12 +1319,12 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz", - "integrity": "sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.7.tgz", + "integrity": "sha512-kFy35VwmwIQwCjwrAQhl3+c/kr292i4KdLPKp5lPH03Ltc51qnFlIADoyPxc/6Naz3ok3WdYKg+KK6AH+D4utg==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1316,12 +1334,12 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz", - "integrity": "sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", + "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1331,13 +1349,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz", - "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1347,12 +1365,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz", - "integrity": "sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", + "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1362,9 +1380,24 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz", - "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.0.tgz", + "integrity": "sha512-FJFdJAqaCpndL+pIf0aeD/qlQwT7QXOvR6Cc8JPvNhKJBi2zc/DPc4g05Y3fbD/0iWAMQFGij4+Xw+4L/BMpTg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -1376,50 +1409,90 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.1.tgz", - "integrity": "sha512-cAzB+UzBIrekfYxyLlFqf/OagTvHLcVBb5vpouzkYkBclRPraiygVnafvAoipErZLI8ANv8Ecn6E/m5qPXD26w==", + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.0.tgz", + "integrity": "sha512-rqDgIbukZ44pqq7NIRPGPGNklshPkvlmvqjdx3OZcGPk4zGIenYkxDTvl3LsSL8gqcc3ZzGmXPE6hR/u/voNOw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-annotate-as-pure": "^7.16.0", + "@babel/helper-module-imports": "^7.16.0", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-jsx": "^7.16.0", + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.12.tgz", - "integrity": "sha512-JDWGuzGNWscYcq8oJVCtSE61a5+XAOos+V0HrxnDieUus4UMnBEosDnY1VJqU5iZ4pA04QY7l0+JvHL1hZEfsw==", + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.0.tgz", + "integrity": "sha512-qq65iSqBRq0Hr3wq57YG2AmW0H6wgTnIzpffTphrUWUgLCOK+zf1f7G0vuOiXrp7dU1qq+fQBoqZ3wCDAkhFzw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.12.10", - "@babel/helper-module-imports": "^7.12.5", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-jsx": "^7.12.1", - "@babel/types": "^7.12.12" + "@babel/plugin-transform-react-jsx": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.12.1.tgz", - "integrity": "sha512-FbpL0ieNWiiBB5tCldX17EtXgmzeEZjFrix72rQYeq9X6nUK38HCaxexzVQrZWXanxKJPKVVIU37gFjEQYkPkA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.16.0.tgz", + "integrity": "sha512-97yCFY+2GvniqOThOSjPor8xUoDiQ0STVWAQMl3pjhJoFVe5DuXDLZCRSZxu9clx+oRCbTiXGgKEG/Yoyo6Y+w==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.12.1.tgz", - "integrity": "sha512-keQ5kBfjJNRc6zZN1/nVHCd6LLIHq4aUKcVnvE/2l+ZZROSbqoiGFRtT5t3Is89XJxBQaP7NLZX2jgGHdZvvFQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.16.0.tgz", + "integrity": "sha512-8yvbGGrHOeb/oyPc9tzNoe9/lmIjz3HLa9Nc5dMGDyNpGjfFrk8D2KdEq9NRkftZzeoQEW6yPQ29TMZtrLiUUA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.0.tgz", + "integrity": "sha512-NC/Bj2MG+t8Ef5Pdpo34Ay74X4Rt804h5y81PwOpfPtmAK3i6CizmQqwyBQzIepz1Yt8wNr2Z2L7Lu3qBMfZMA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.0", + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz", - "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", + "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", "dev": true, "dependencies": { "regenerator-transform": "^0.14.2" @@ -1432,12 +1505,12 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz", - "integrity": "sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", + "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1446,25 +1519,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz", - "integrity": "sha512-jIgkljDdq4RYDnJyQsiWbdvGeei/0MOTtSHKO/rfbd/mXBxNpdlulMx49L0HQ4pug1fXannxoqCI+fYSle9eSw==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "resolve": "^1.8.1", - "semver": "^5.5.1" - } - }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz", - "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1474,13 +1535,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz", - "integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", + "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" }, "engines": { "node": ">=6.9.0" @@ -1490,12 +1551,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz", - "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1505,12 +1566,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz", - "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", + "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1520,12 +1581,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz", - "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", + "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1535,12 +1596,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz", - "integrity": "sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1550,13 +1611,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz", - "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1580,31 +1641,32 @@ "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" }, "node_modules/@babel/preset-env": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.15.0.tgz", - "integrity": "sha512-FhEpCNFCcWW3iZLg0L2NPE9UerdtsCR6ZcsGHUX6Om6kbCQeL5QZDqFDmeNHC6/fy6UH3jEge7K4qG5uC9In0Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.7.tgz", + "integrity": "sha512-urX3Cee4aOZbRWOSa3mKPk0aqDikfILuo+C7qq7HY0InylGNZ1fekq9jmlr3pLWwZHF4yD7heQooc2Pow2KMyQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5", - "@babel/plugin-proposal-async-generator-functions": "^7.14.9", - "@babel/plugin-proposal-class-properties": "^7.14.5", - "@babel/plugin-proposal-class-static-block": "^7.14.5", - "@babel/plugin-proposal-dynamic-import": "^7.14.5", - "@babel/plugin-proposal-export-namespace-from": "^7.14.5", - "@babel/plugin-proposal-json-strings": "^7.14.5", - "@babel/plugin-proposal-logical-assignment-operators": "^7.14.5", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5", - "@babel/plugin-proposal-numeric-separator": "^7.14.5", - "@babel/plugin-proposal-object-rest-spread": "^7.14.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.14.5", - "@babel/plugin-proposal-optional-chaining": "^7.14.5", - "@babel/plugin-proposal-private-methods": "^7.14.5", - "@babel/plugin-proposal-private-property-in-object": "^7.14.5", - "@babel/plugin-proposal-unicode-property-regex": "^7.14.5", + "@babel/compat-data": "^7.16.4", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-async-generator-functions": "^7.16.7", + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-proposal-class-static-block": "^7.16.7", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.16.7", + "@babel/plugin-proposal-json-strings": "^7.16.7", + "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.16.7", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-private-methods": "^7.16.7", + "@babel/plugin-proposal-private-property-in-object": "^7.16.7", + "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", "@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", @@ -1619,44 +1681,44 @@ "@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.14.5", - "@babel/plugin-transform-async-to-generator": "^7.14.5", - "@babel/plugin-transform-block-scoped-functions": "^7.14.5", - "@babel/plugin-transform-block-scoping": "^7.14.5", - "@babel/plugin-transform-classes": "^7.14.9", - "@babel/plugin-transform-computed-properties": "^7.14.5", - "@babel/plugin-transform-destructuring": "^7.14.7", - "@babel/plugin-transform-dotall-regex": "^7.14.5", - "@babel/plugin-transform-duplicate-keys": "^7.14.5", - "@babel/plugin-transform-exponentiation-operator": "^7.14.5", - "@babel/plugin-transform-for-of": "^7.14.5", - "@babel/plugin-transform-function-name": "^7.14.5", - "@babel/plugin-transform-literals": "^7.14.5", - "@babel/plugin-transform-member-expression-literals": "^7.14.5", - "@babel/plugin-transform-modules-amd": "^7.14.5", - "@babel/plugin-transform-modules-commonjs": "^7.15.0", - "@babel/plugin-transform-modules-systemjs": "^7.14.5", - "@babel/plugin-transform-modules-umd": "^7.14.5", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.9", - "@babel/plugin-transform-new-target": "^7.14.5", - "@babel/plugin-transform-object-super": "^7.14.5", - "@babel/plugin-transform-parameters": "^7.14.5", - "@babel/plugin-transform-property-literals": "^7.14.5", - "@babel/plugin-transform-regenerator": "^7.14.5", - "@babel/plugin-transform-reserved-words": "^7.14.5", - "@babel/plugin-transform-shorthand-properties": "^7.14.5", - "@babel/plugin-transform-spread": "^7.14.6", - "@babel/plugin-transform-sticky-regex": "^7.14.5", - "@babel/plugin-transform-template-literals": "^7.14.5", - "@babel/plugin-transform-typeof-symbol": "^7.14.5", - "@babel/plugin-transform-unicode-escapes": "^7.14.5", - "@babel/plugin-transform-unicode-regex": "^7.14.5", - "@babel/preset-modules": "^0.1.4", - "@babel/types": "^7.15.0", - "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.2", - "babel-plugin-polyfill-regenerator": "^0.2.2", - "core-js-compat": "^3.16.0", + "@babel/plugin-transform-arrow-functions": "^7.16.7", + "@babel/plugin-transform-async-to-generator": "^7.16.7", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.16.7", + "@babel/plugin-transform-classes": "^7.16.7", + "@babel/plugin-transform-computed-properties": "^7.16.7", + "@babel/plugin-transform-destructuring": "^7.16.7", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.16.7", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.16.7", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.16.7", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.16.7", + "@babel/plugin-transform-modules-systemjs": "^7.16.7", + "@babel/plugin-transform-modules-umd": "^7.16.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.7", + "@babel/plugin-transform-new-target": "^7.16.7", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.16.7", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.16.7", + "@babel/plugin-transform-reserved-words": "^7.16.7", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.16.7", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.16.7", + "@babel/plugin-transform-typeof-symbol": "^7.16.7", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.16.7", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.4.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.19.1", "semver": "^6.3.0" }, "engines": { @@ -1676,9 +1738,9 @@ } }, "node_modules/@babel/preset-modules": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", @@ -1686,25 +1748,15 @@ "@babel/plugin-transform-dotall-regex": "^7.4.4", "@babel/types": "^7.4.4", "esutils": "^2.0.2" - } - }, - "node_modules/@babel/preset-react": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", - "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-transform-react-display-name": "^7.0.0", - "@babel/plugin-transform-react-jsx": "^7.0.0", - "@babel/plugin-transform-react-jsx-self": "^7.0.0", - "@babel/plugin-transform-react-jsx-source": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/register": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.15.3.tgz", - "integrity": "sha512-mj4IY1ZJkorClxKTImccn4T81+UKTo4Ux0+OFSV9hME1ooqS9UV+pJ6BjD0qXPK4T3XW/KNa79XByjeEMZz+fw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.16.7.tgz", + "integrity": "sha512-Ft+cuxorVxFj4RrPDs9TbJNE7ZbuJTyazUC6jLWRvBQT/qIDZPMe7MHgjlrA+11+XDLh+I0Pnx7sxPp4LRhzcA==", "dev": true, "dependencies": { "clone-deep": "^4.0.1", @@ -1721,19 +1773,23 @@ } }, "node_modules/@babel/runtime": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz", - "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==", + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz", + "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==", "dependencies": { "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.15.3.tgz", - "integrity": "sha512-30A3lP+sRL6ml8uhoJSs+8jwpKzbw8CqBvDc1laeptxPm5FahumJxirigcbD2qTs71Sonvj1cyZB0OKGAmxQ+A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.7.tgz", + "integrity": "sha512-MiYR1yk8+TW/CpOD0CyX7ve9ffWTKqLk/L6pk8TPl0R8pNi+1pFY8fH9yET55KlvukQ4PAWfXsGr2YHVjcI4Pw==", + "dev": true, "dependencies": { - "core-js-pure": "^3.16.0", + "core-js-pure": "^3.19.0", "regenerator-runtime": "^0.13.4" }, "engines": { @@ -1741,32 +1797,33 @@ } }, "node_modules/@babel/template": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", - "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", - "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.7.tgz", + "integrity": "sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.15.0", - "@babel/types": "^7.15.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1790,12 +1847,12 @@ "dev": true }, "node_modules/@babel/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", - "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz", + "integrity": "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1803,201 +1860,495 @@ } }, "node_modules/@cypress/browserify-preprocessor": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cypress/browserify-preprocessor/-/browserify-preprocessor-3.0.1.tgz", - "integrity": "sha512-sErmFSEr5287bLMRl0POGnyFtJCs/lSk5yxrUIJUIHZ8eDvtTEr0V93xRgLjJVG54gJU4MbpHy1mRPA9VZbtQA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@cypress/browserify-preprocessor/-/browserify-preprocessor-3.0.2.tgz", + "integrity": "sha512-y6mlFR+IR2cqcm3HabSp7AEcX9QfF1EUL4eOaw/7xexdhmdQU8ez6piyRopZQob4BK8oKTsc9PkupsU2rzjqMA==", "dev": true, "dependencies": { - "@babel/core": "7.4.5", - "@babel/plugin-proposal-class-properties": "7.3.0", - "@babel/plugin-proposal-object-rest-spread": "7.3.2", - "@babel/plugin-transform-runtime": "7.2.0", - "@babel/preset-env": "7.4.5", - "@babel/preset-react": "7.0.0", - "@babel/runtime": "7.3.1", - "babel-plugin-add-module-exports": "1.0.2", - "babelify": "10.0.0", - "bluebird": "3.5.3", - "browserify": "16.2.3", - "coffeeify": "3.0.1", - "coffeescript": "1.12.7", - "debug": "4.1.1", - "fs-extra": "9.0.0", - "lodash.clonedeep": "4.5.0", + "@babel/core": "^7.16.0", + "@babel/plugin-proposal-class-properties": "^7.16.0", + "@babel/plugin-proposal-object-rest-spread": "^7.16.0", + "@babel/plugin-transform-runtime": "^7.16.0", + "@babel/preset-env": "^7.16.0", + "@babel/preset-react": "^7.16.0", + "@babel/runtime": "^7.16.0", + "babel-plugin-add-module-exports": "^1.0.4", + "babelify": "^10.0.0", + "bluebird": "^3.7.2", + "browserify": "^16.2.3", + "coffeeify": "^3.0.1", + "coffeescript": "^1.12.7", + "debug": "^4.3.2", + "fs-extra": "^9.0.0", + "lodash.clonedeep": "^4.5.0", "through2": "^2.0.0", - "watchify": "3.11.1" + "watchify": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/@cypress/browserify-preprocessor/node_modules/@babel/core": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.5.tgz", - "integrity": "sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==", + "node_modules/@cypress/browserify-preprocessor/node_modules/@babel/plugin-transform-runtime": { + "version": "7.16.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.4.tgz", + "integrity": "sha512-pru6+yHANMTukMtEZGC4fs7XPwg35v8sj5CIEmE+gEkFljFiVJxEWxx/7ZDkTK+iZRYo1bFXBtfIN95+K3cJ5A==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.4", - "@babel/helpers": "^7.4.4", - "@babel/parser": "^7.4.5", - "@babel/template": "^7.4.4", - "@babel/traverse": "^7.4.5", - "@babel/types": "^7.4.4", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.11", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "@babel/helper-module-imports": "^7.16.0", + "@babel/helper-plugin-utils": "^7.14.5", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.4.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "semver": "^6.3.0" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@cypress/browserify-preprocessor/node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.0.tgz", - "integrity": "sha512-wNHxLkEKTQ2ay0tnsam2z7fGZUi+05ziDJflEt3AZTP3oXLKHJp9HqhfroB/vdMvt3sda9fAbq7FsG8QPDrZBg==", + "node_modules/@cypress/browserify-preprocessor/node_modules/@babel/preset-react": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.0.tgz", + "integrity": "sha512-d31IFW2bLRB28uL1WoElyro8RH5l6531XfxMtCeCmp6RVAF1uTfxxUA0LH1tXl+psZdwfmIbwoG4U5VwgbhtLw==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.3.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "@babel/plugin-transform-react-display-name": "^7.16.0", + "@babel/plugin-transform-react-jsx": "^7.16.0", + "@babel/plugin-transform-react-jsx-development": "^7.16.0", + "@babel/plugin-transform-react-pure-annotations": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@cypress/browserify-preprocessor/node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.2.tgz", - "integrity": "sha512-DjeMS+J2+lpANkYLLO+m6GjoTMygYglKmRe6cDTbFv3L9i6mmiE8fe6B8MtCSLZpVXscD5kn7s6SgtHrDoBWoA==", + "node_modules/@cypress/browserify-preprocessor/node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/@cypress/browserify-preprocessor/node_modules/@babel/preset-env": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.5.tgz", - "integrity": "sha512-f2yNVXM+FsR5V8UwcFeIHzHWgnhXg3NpRmy0ADvALpnhB0SLbCvrCRr4BLOUYbQNLS+Z0Yer46x9dJXpXewI7w==", + "node_modules/@cypress/browserify-preprocessor/node_modules/babel-plugin-add-module-exports": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-1.0.4.tgz", + "integrity": "sha512-g+8yxHUZ60RcyaUpfNzy56OtWW+x9cyEe9j+CranqLiqbju2yf/Cy6ZtYK40EZxtrdHllzlVZgLmcOUCTlJ7Jg==", + "dev": true + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.2.0", - "@babel/plugin-proposal-json-strings": "^7.2.0", - "@babel/plugin-proposal-object-rest-spread": "^7.4.4", - "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-syntax-async-generators": "^7.2.0", - "@babel/plugin-syntax-json-strings": "^7.2.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", - "@babel/plugin-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.4.4", - "@babel/plugin-transform-block-scoped-functions": "^7.2.0", - "@babel/plugin-transform-block-scoping": "^7.4.4", - "@babel/plugin-transform-classes": "^7.4.4", - "@babel/plugin-transform-computed-properties": "^7.2.0", - "@babel/plugin-transform-destructuring": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/plugin-transform-duplicate-keys": "^7.2.0", - "@babel/plugin-transform-exponentiation-operator": "^7.2.0", - "@babel/plugin-transform-for-of": "^7.4.4", - "@babel/plugin-transform-function-name": "^7.4.4", - "@babel/plugin-transform-literals": "^7.2.0", - "@babel/plugin-transform-member-expression-literals": "^7.2.0", - "@babel/plugin-transform-modules-amd": "^7.2.0", - "@babel/plugin-transform-modules-commonjs": "^7.4.4", - "@babel/plugin-transform-modules-systemjs": "^7.4.4", - "@babel/plugin-transform-modules-umd": "^7.2.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.5", - "@babel/plugin-transform-new-target": "^7.4.4", - "@babel/plugin-transform-object-super": "^7.2.0", - "@babel/plugin-transform-parameters": "^7.4.4", - "@babel/plugin-transform-property-literals": "^7.2.0", - "@babel/plugin-transform-regenerator": "^7.4.5", - "@babel/plugin-transform-reserved-words": "^7.2.0", - "@babel/plugin-transform-shorthand-properties": "^7.2.0", - "@babel/plugin-transform-spread": "^7.2.0", - "@babel/plugin-transform-sticky-regex": "^7.2.0", - "@babel/plugin-transform-template-literals": "^7.4.4", - "@babel/plugin-transform-typeof-symbol": "^7.2.0", - "@babel/plugin-transform-unicode-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "browserslist": "^4.6.0", - "core-js-compat": "^3.1.1", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.5.0" + "engines": { + "node": ">=8" } }, - "node_modules/@cypress/browserify-preprocessor/node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "node_modules/@cypress/browserify-preprocessor/node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@cypress/browserify-preprocessor/node_modules/@babel/runtime": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.1.tgz", - "integrity": "sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==", + "node_modules/@cypress/browserify-preprocessor/node_modules/browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", "dev": true, "dependencies": { - "regenerator-runtime": "^0.12.0" + "resolve": "^1.17.0" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "dev": true, + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, "node_modules/@cypress/browserify-preprocessor/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "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.1" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/@cypress/browserify-preprocessor/node_modules/fs-extra": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", - "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", - "universalify": "^1.0.0" + "universalify": "^2.0.0" }, "engines": { "node": ">=10" } }, - "node_modules/@cypress/browserify-preprocessor/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "node_modules/@cypress/browserify-preprocessor/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "node_modules/@cypress/browserify-preprocessor/node_modules/regenerator-runtime": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", - "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", - "dev": true - }, - "node_modules/@cypress/code-coverage": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/@cypress/code-coverage/-/code-coverage-3.9.10.tgz", - "integrity": "sha512-aJokd9B1/cI8uQAH4tPw9yuZg7a/bdl1xO4xSeO4ly5Tlj8L3/eJ2vvJf5RcfHAZQE1OMOYY7ZtPuBBE8eItYw==", + "node_modules/@cypress/browserify-preprocessor/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "dependencies": { - "@cypress/browserify-preprocessor": "3.0.1", + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/@cypress/browserify-preprocessor/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/@cypress/browserify-preprocessor/node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/stream-http": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", + "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", + "dev": true, + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/stream-http/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/util": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", + "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/watchify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/watchify/-/watchify-4.0.0.tgz", + "integrity": "sha512-2Z04dxwoOeNxa11qzWumBTgSAohTC0+ScuY7XMenPnH+W2lhTcpEOJP4g2EIG/SWeLadPk47x++Yh+8BqPM/lA==", + "dev": true, + "dependencies": { + "anymatch": "^3.1.0", + "browserify": "^17.0.0", + "chokidar": "^3.4.0", + "defined": "^1.0.0", + "outpipe": "^1.1.0", + "through2": "^4.0.2", + "xtend": "^4.0.2" + }, + "bin": { + "watchify": "bin/cmd.js" + }, + "engines": { + "node": ">= 8.10.0" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/watchify/node_modules/browserify": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz", + "integrity": "sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w==", + "dev": true, + "dependencies": { + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^2.0.0", + "browserify-zlib": "~0.2.0", + "buffer": "~5.2.1", + "cached-path-relative": "^1.0.0", + "concat-stream": "^1.6.0", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.1", + "domain-browser": "^1.2.0", + "duplexer2": "~0.1.2", + "events": "^3.0.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.2.1", + "JSONStream": "^1.0.3", + "labeled-stream-splicer": "^2.0.0", + "mkdirp-classic": "^0.5.2", + "module-deps": "^6.2.3", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "^1.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum-object": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^3.0.0", + "stream-http": "^3.0.0", + "string_decoder": "^1.1.1", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "0.0.1", + "url": "~0.11.0", + "util": "~0.12.0", + "vm-browserify": "^1.0.0", + "xtend": "^4.0.0" + }, + "bin": { + "browserify": "bin/cmd.js" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/watchify/node_modules/browserify/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/watchify/node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/@cypress/browserify-preprocessor/node_modules/watchify/node_modules/through2/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@cypress/code-coverage": { + "version": "3.9.12", + "resolved": "https://registry.npmjs.org/@cypress/code-coverage/-/code-coverage-3.9.12.tgz", + "integrity": "sha512-2QuDSQ2ovz2ZsbQImM917q+9JmEq4afC4kpgHe2o3rTQxUrs7CdHM84rT8XKl0gJIXmbMcNq2rZqe40/eFmCFw==", + "dev": true, + "dependencies": { + "@cypress/browserify-preprocessor": "3.0.2", "chalk": "4.1.2", - "dayjs": "1.10.6", - "debug": "4.3.2", + "dayjs": "1.10.7", + "debug": "4.3.3", "execa": "4.1.0", "globby": "11.0.4", "istanbul-lib-coverage": "3.0.0", @@ -2058,9 +2409,9 @@ "dev": true }, "node_modules/@cypress/code-coverage/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" @@ -2115,13 +2466,13 @@ } }, "node_modules/@cypress/fiddle": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@cypress/fiddle/-/fiddle-1.19.2.tgz", - "integrity": "sha512-Ovl6kk/F/73ZrSjGx95FiuO/eIvfsVMzMsMtc1YOYD7ctiBqGCU6ucy65jNzj+VQRn59FStPyfEHt1udLxfTqQ==", + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/@cypress/fiddle/-/fiddle-1.19.3.tgz", + "integrity": "sha512-g8YMD6vRQk2LWil8BWo9hs4unHD2wvxkDm5uzeeYHjgy4eWIhFizSov7TNjUU1keX5svA8aXsh3x+yz8Q6dgzw==", "dev": true, "dependencies": { - "@cypress/browserify-preprocessor": "2.2.4", - "@textlint/markdown-to-ast": "6.2.6", + "@cypress/browserify-preprocessor": "3.0.1", + "@textlint/markdown-to-ast": "12.0.0", "arg": "4.1.3", "common-tags": "1.8.0", "debug": "4.2.0", @@ -2165,6 +2516,9 @@ "dependencies": { "@babel/helper-create-class-features-plugin": "^7.3.0", "@babel/helper-plugin-utils": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@cypress/fiddle/node_modules/@babel/plugin-proposal-object-rest-spread": { @@ -2175,6 +2529,24 @@ "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@cypress/fiddle/node_modules/@babel/plugin-transform-runtime": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz", + "integrity": "sha512-jIgkljDdq4RYDnJyQsiWbdvGeei/0MOTtSHKO/rfbd/mXBxNpdlulMx49L0HQ4pug1fXannxoqCI+fYSle9eSw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@cypress/fiddle/node_modules/@babel/preset-env": { @@ -2231,17 +2603,44 @@ "invariant": "^2.2.2", "js-levenshtein": "^1.1.3", "semver": "^5.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@cypress/fiddle/node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.0.tgz", - "integrity": "sha512-B4qphdSTp0nLsWcuei07JPKeZej4+Hd22MdnulJXQa1nCcGSBlk8FiqenGERaPZ+PuYhz4Li2Wjc8yfJvHgUMw==", + "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==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.13.0" + "@babel/compat-data": "^7.16.0", + "@babel/helper-compilation-targets": "^7.16.0", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@cypress/fiddle/node_modules/@babel/preset-react": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", + "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@cypress/fiddle/node_modules/@babel/runtime": { @@ -2254,9 +2653,9 @@ } }, "node_modules/@cypress/fiddle/node_modules/@cypress/browserify-preprocessor": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@cypress/browserify-preprocessor/-/browserify-preprocessor-2.2.4.tgz", - "integrity": "sha512-kMjkIFe6qka8Tkm9N3BrMB+Nn7WEAHIzEd3gfVoDL17Tr40xyOnKGuMhEkff1scd3RV3bjQxwQ9BQ6kI2nToAQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cypress/browserify-preprocessor/-/browserify-preprocessor-3.0.1.tgz", + "integrity": "sha512-sErmFSEr5287bLMRl0POGnyFtJCs/lSk5yxrUIJUIHZ8eDvtTEr0V93xRgLjJVG54gJU4MbpHy1mRPA9VZbtQA==", "dev": true, "dependencies": { "@babel/core": "7.4.5", @@ -2273,19 +2672,20 @@ "coffeeify": "3.0.1", "coffeescript": "1.12.7", "debug": "4.1.1", - "fs-extra": "7.0.1", + "fs-extra": "9.0.0", "lodash.clonedeep": "4.5.0", "through2": "^2.0.0", "watchify": "3.11.1" }, "engines": { - "node": ">=6.5" + "node": ">=8" } }, "node_modules/@cypress/fiddle/node_modules/@cypress/browserify-preprocessor/node_modules/debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", "dev": true, "dependencies": { "ms": "^2.1.1" @@ -2295,12 +2695,33 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", "dev": true, "dependencies": { "ms": "2.1.2" }, "engines": { "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@cypress/fiddle/node_modules/fs-extra": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", + "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + }, + "engines": { + "node": ">=10" } }, "node_modules/@cypress/fiddle/node_modules/ms": { @@ -2315,10 +2736,19 @@ "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", "dev": true }, + "node_modules/@cypress/fiddle/node_modules/universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/@cypress/request": { - "version": "2.88.6", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.6.tgz", - "integrity": "sha512-z0UxBE/+qaESAHY9p9sM2h8Y4XqtsbDCt0/DPOrqA/RZgKi4PkxdpXyK4wCCnSk1xHqWHZZAE+gV6aDAR6+caQ==", + "version": "2.88.10", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", + "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==", "dev": true, "dependencies": { "aws-sign2": "~0.7.0", @@ -2328,8 +2758,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", + "http-signature": "~1.3.6", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", @@ -2345,6 +2774,41 @@ "node": ">= 6" } }, + "node_modules/@cypress/request/node_modules/http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/@cypress/request/node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/@cypress/request/node_modules/jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, "node_modules/@cypress/request/node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -2401,33 +2865,20 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.10.8", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.10.8.tgz", - "integrity": "sha512-3P1JiGL4xaR9PoTKUHa2N/LKwa2/eUdRqGwijMWWgBqbFEqJUVpmaOi2TcjcemrsRMgFLBzQCK4ToPhrSVDiFQ==", - "dev": true, - "dependencies": { - "comment-parser": "1.2.4", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "1.1.1" - }, - "engines": { - "node": "^12 || ^14 || ^16" - } - }, "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" }, @@ -2436,9 +2887,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" @@ -2452,27 +2903,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" @@ -2490,70 +2927,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", @@ -2569,49 +2948,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", @@ -3074,12 +3410,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", @@ -3258,9 +3588,9 @@ } }, "node_modules/@rollup/plugin-commonjs": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-18.0.0.tgz", - "integrity": "sha512-fj92shhg8luw7XbA0HowAqz90oo7qtLGwqTKbyZ8pmOyH8ui5e+u0wPEgeHLH3djcVma6gUCUrjY6w5R2o1u6g==", + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-18.1.0.tgz", + "integrity": "sha512-h3e6T9rUxVMAQswpDIobfUHn/doMzM9sgkMrsMWCFLmB84PSoC8mV8tOloAJjSRwdqhXBqstlX2BwBpHJvbhxg==", "dev": true, "dependencies": { "@rollup/pluginutils": "^3.1.0", @@ -3285,14 +3615,14 @@ "dev": true }, "node_modules/@rollup/plugin-dynamic-import-vars": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-dynamic-import-vars/-/plugin-dynamic-import-vars-1.4.0.tgz", - "integrity": "sha512-oDeBDYJkD+VleSqSmWZo4h7iMHFYgEx/XVnJJZhCGuqkrS9QwOubESyWMqujBuUMeIByv954RvBTFvkAKlLh4A==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-dynamic-import-vars/-/plugin-dynamic-import-vars-1.4.2.tgz", + "integrity": "sha512-SEaS9Pf0RyaZ/oJ1knLZT+Fu0X6DlyTfUcoE7XKkiKJjNaB+8SLoHmDVRhomo5RpWHPyd+B00G/bE5R5+Q+HEg==", "dev": true, "dependencies": { - "@rollup/pluginutils": "^3.1.0", + "@rollup/pluginutils": "^4.1.2", "estree-walker": "^2.0.1", - "globby": "^11.0.1", + "fast-glob": "^3.2.7", "magic-string": "^0.25.7" }, "engines": { @@ -3302,6 +3632,19 @@ "rollup": "^1.20.0||^2.0.0" } }, + "node_modules/@rollup/plugin-dynamic-import-vars/node_modules/@rollup/pluginutils": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.2.tgz", + "integrity": "sha512-ROn4qvkxP9SyPeHaf7uQC/GPFY6L/OWy9+bd9AwcjOAWQwxRscoEyAUD8qCY5o5iL4jqQwoLk2kaTKJPb/HwzQ==", + "dev": true, + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/@rollup/plugin-dynamic-import-vars/node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -3319,9 +3662,9 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.4.tgz", - "integrity": "sha512-eYq4TFy40O8hjeDs+sIxEH/jc9lyuI2k9DM557WN6rO5OpnC2qXMBNj4IKH1oHrnAazL49C5p0tgP0/VpqJ+/w==", + "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", @@ -3339,9 +3682,9 @@ } }, "node_modules/@rollup/plugin-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-3.0.0.tgz", - "integrity": "sha512-3c7JCbMuYXM4PbPWT4+m/4Y6U60SgsnDT/cCyAyUKwFHg7pTSfsSQzIpETha3a3ig6OdOKzZz87D9ZXIK3qsDg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-3.0.1.tgz", + "integrity": "sha512-989J5oRzf3mm0pO/0djTijdfEh9U3n63BIXN5X7T4U9BP+fN4oxQ6DvDuBvFaHA6scaHQRclqmKQEkBhB7k7Hg==", "dev": true, "dependencies": { "@rollup/pluginutils": "^3.1.0", @@ -3424,36 +3767,42 @@ "dev": true }, "node_modules/@textlint/ast-node-types": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-4.4.1.tgz", - "integrity": "sha512-2QBwlqi2SU83vTHibfdTxGiLdIqR0btNyMGfVl0bwA6FI85HnSYoGFLrdCnq2V0nxpbhuvwzcm2Ja81w0VkMGA==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-12.1.0.tgz", + "integrity": "sha512-UlxqemrV/EnGTCl26OU7JhtFJpH7NZdgXvnsuII604orcIkvywUA1GGlg51grfbfqi+ar4zRsOb6fVbcbMZnKA==", "dev": true }, "node_modules/@textlint/markdown-to-ast": { - "version": "6.2.6", - "resolved": "https://registry.npmjs.org/@textlint/markdown-to-ast/-/markdown-to-ast-6.2.6.tgz", - "integrity": "sha512-TjZTMGYla9Nznegy0r23EEzNMfWva0oksj+48aqMlbQ+UvBA5vdEC0VzCO3l0Z137RgEJ+glInbvEilo2zcjZg==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@textlint/markdown-to-ast/-/markdown-to-ast-12.0.0.tgz", + "integrity": "sha512-XaiuePJVDGVIwdjIiITdbdRXZDFnAFY/so3Rb8qAId/Qq9fKPUvgefMkdIG73wUC7LzhrAzH6/CuEO+f77HR5g==", "dev": true, "dependencies": { - "@textlint/ast-node-types": "^4.3.5", + "@textlint/ast-node-types": "^12.0.0", "debug": "^4.3.1", - "remark-frontmatter": "^1.3.3", - "remark-parse": "^5.0.0", - "structured-source": "^3.0.2", + "remark-footnotes": "^3.0.0", + "remark-frontmatter": "^3.0.0", + "remark-gfm": "^1.0.0", + "remark-parse": "^9.0.0", "traverse": "^0.6.6", - "unified": "^6.2.0" + "unified": "^9.2.1" } }, "node_modules/@textlint/markdown-to-ast/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" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/@textlint/markdown-to-ast/node_modules/ms": { @@ -3487,9 +3836,9 @@ } }, "node_modules/@types/body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", "dev": true, "dependencies": { "@types/connect": "*", @@ -3571,9 +3920,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz", - "integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==", + "version": "4.17.26", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz", + "integrity": "sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==", "dev": true, "dependencies": { "@types/node": "*", @@ -3601,9 +3950,9 @@ } }, "node_modules/@types/http-assert": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.2.tgz", - "integrity": "sha512-Ddzuzv/bB2prZnJKlS1sEYhaeT50wfJjhcTTTQLjEsEZJlk3XB4Xohieyq+P4VXIzg7lrQ1Spd/PfRnBpQsdqA==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.3.tgz", + "integrity": "sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==", "dev": true }, "node_modules/@types/http-errors": { @@ -3713,9 +4062,9 @@ "dev": true }, "node_modules/@types/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-ARATsLdrGPUnaBvxLhUlnltcMgn7pQG312S8ccdYlnyijabrX9RN/KN/iGj9Am96CoW8e/K9628BA7Bv4XHdrA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", + "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==", "dev": true }, "node_modules/@types/qs": { @@ -3844,24 +4193,23 @@ } }, "node_modules/@web/dev-server": { - "version": "0.1.22", - "resolved": "https://registry.npmjs.org/@web/dev-server/-/dev-server-0.1.22.tgz", - "integrity": "sha512-8PZxz2PGK9Ndr0C2LtWHrTzPKkDYTP/IvEMs9nrIebQWxvVjxI/HpvNfli3ivvCtvvcJFI26FvfWaAWDq14GgQ==", + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/@web/dev-server/-/dev-server-0.1.29.tgz", + "integrity": "sha512-oDz6vC9JEDZd4ZTno+SV57zCpsQl9v5LOkGuWGyei5gx5xu8NVDvh2IgTugz6DhZnffsSE6Zi0ubs+AhonLnGA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.11", - "@rollup/plugin-node-resolve": "^11.0.1", "@types/command-line-args": "^5.0.0", "@web/config-loader": "^0.1.3", - "@web/dev-server-core": "^0.3.14", - "@web/dev-server-rollup": "^0.3.9", + "@web/dev-server-core": "^0.3.17", + "@web/dev-server-rollup": "^0.3.13", "camelcase": "^6.2.0", - "chalk": "^4.1.0", "command-line-args": "^5.1.1", "command-line-usage": "^6.1.1", "debounce": "^1.2.0", "deepmerge": "^4.2.2", "ip": "^1.1.5", + "nanocolors": "^0.2.1", "open": "^8.0.2", "portfinder": "^1.0.28" }, @@ -3874,9 +4222,9 @@ } }, "node_modules/@web/dev-server-core": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@web/dev-server-core/-/dev-server-core-0.3.14.tgz", - "integrity": "sha512-QHWGbkLI7qZVkELd6a7R4llRF9zydwbZagAeiJRvOIIiDhG5Uu9DfAWAQL+RSCb2hqBlEnaVAK4keNffKol4rQ==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@web/dev-server-core/-/dev-server-core-0.3.17.tgz", + "integrity": "sha512-vN1dwQ8yDHGiAvCeUo9xFfjo+pFl8TW+pON7k9kfhbegrrB8CKhJDUxmHbZsyQUmjf/iX57/LhuWj1xGhRL8AA==", "dev": true, "dependencies": { "@types/koa": "^2.11.6", @@ -3884,7 +4232,7 @@ "@web/parse5-utils": "^1.2.0", "chokidar": "^3.4.3", "clone": "^2.1.2", - "es-module-lexer": "^0.7.1", + "es-module-lexer": "^0.9.0", "get-stream": "^6.0.0", "is-stream": "^2.0.0", "isbinaryfile": "^4.0.6", @@ -4059,111 +4407,23 @@ } }, "node_modules/@web/dev-server-rollup": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@web/dev-server-rollup/-/dev-server-rollup-0.3.9.tgz", - "integrity": "sha512-8NOV8GxcDXk9u+hsVYllGiMhcORYMFK+LtLT4HIg3+emW64j0MynttowBoOFpgwv7YOuVQ6lWe1kmJxiI+TRdg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@web/dev-server-rollup/-/dev-server-rollup-0.3.13.tgz", + "integrity": "sha512-QaxEtsdL6+fktIa1ZL8VEtq4U7WB7ikKEnxkbhUpFknB+WSvwx6DUrvyBDuPckunpczCnljXBFPugu+2W6N8Fg==", "dev": true, "dependencies": { - "@web/dev-server-core": "^0.3.3", - "chalk": "^4.1.0", + "@rollup/plugin-node-resolve": "^11.0.1", + "@web/dev-server-core": "^0.3.16", + "nanocolors": "^0.2.1", "parse5": "^6.0.1", - "rollup": "^2.56.2", - "whatwg-url": "^9.0.0" + "rollup": "^2.58.0", + "whatwg-url": "^11.0.0" }, "engines": { "node": ">=10.0.0" } }, - "node_modules/@web/dev-server-rollup/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@web/dev-server-rollup/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@web/dev-server-rollup/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@web/dev-server-rollup/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@web/dev-server-rollup/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@web/dev-server-rollup/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/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@web/dev-server-rollup/node_modules/whatwg-url": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-9.1.0.tgz", - "integrity": "sha512-CQ0UcrPHyomtlOCot1TL77WyMIm/bCwrJ2D6AOKGwEczU9EpyoqAokfqrf/MioU9kHcMsmJZcg1egXix2KYEsA==", - "dev": true, - "dependencies": { - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@web/dev-server/node_modules/@rollup/plugin-node-resolve": { + "node_modules/@web/dev-server-rollup/node_modules/@rollup/plugin-node-resolve": { "version": "11.2.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", @@ -4183,6 +4443,55 @@ "rollup": "^1.20.0||^2.0.0" } }, + "node_modules/@web/dev-server-rollup/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/node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@web/dev-server-rollup/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@web/dev-server-rollup/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@web/dev-server-rollup/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@web/dev-server/node_modules/array-back": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", @@ -4201,61 +4510,6 @@ "node": ">=10" } }, - "node_modules/@web/dev-server/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@web/dev-server/node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@web/dev-server/node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@web/dev-server/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@web/dev-server/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/@web/dev-server/node_modules/command-line-usage": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", @@ -4285,15 +4539,6 @@ "node": ">=4" } }, - "node_modules/@web/dev-server/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@web/dev-server/node_modules/typical": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", @@ -4370,9 +4615,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" @@ -4591,9 +4836,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" @@ -4617,12 +4862,6 @@ "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==", "dev": true }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", - "dev": true - }, "node_modules/anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", @@ -4737,16 +4976,16 @@ } }, "node_modules/array-includes": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", - "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", + "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", - "is-string": "^1.0.5" + "is-string": "^1.0.7" }, "engines": { "node": ">= 0.4" @@ -4774,14 +5013,31 @@ } }, "node_modules/array.prototype.flat": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", + "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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.18.0-next.1" + "es-abstract": "^1.19.0" }, "engines": { "node": ">= 0.4" @@ -4875,15 +5131,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", @@ -4940,6 +5187,18 @@ "node": ">= 4.5.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -4955,15 +5214,6 @@ "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==", "dev": true }, - "node_modules/axe-core": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.3.tgz", - "integrity": "sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/axios": { "version": "0.21.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", @@ -4978,7 +5228,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-1.0.2.tgz", "integrity": "sha512-4paN7RivvU3Rzju1vGSHWPjO8Y0rI6droWvSFKI6dvEQ4mvoV0zGojnlzVRfI6N8zISo6VERXt3coIuVmzuvNg==", "dev": true, - "dependencies": { + "optionalDependencies": { "chokidar": "^2.0.4" } }, @@ -4992,13 +5242,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", - "integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.0.tgz", + "integrity": "sha512-wMDoBJ6uG4u4PNFh72Ty6t3EgfA91puCuAwKIazbQlci+ENb/UU9A3xG5lutjUIiXCIn1CY5L15r9LimiJyrSA==", "dev": true, "dependencies": { "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.2.2", + "@babel/helper-define-polyfill-provider": "^0.3.0", "semver": "^6.1.1" }, "peerDependencies": { @@ -5015,25 +5265,25 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.3.tgz", - "integrity": "sha512-rCOFzEIJpJEAU14XCcV/erIf/wZQMmMT5l5vXOpL5uoznyOGfDIjPj6FVytMvtzaKSTSVKouOCTPJ5OMUZH30g==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz", + "integrity": "sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.2.2", - "core-js-compat": "^3.14.0" + "@babel/helper-define-polyfill-provider": "^0.3.0", + "core-js-compat": "^3.18.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz", - "integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.0.tgz", + "integrity": "sha512-dhAPTDLGoMW5/84wkgwiLRwMnio2i1fUe53EuvtKMv0pn2p3S8OCoV1xAzfJPl0KOX7IB89s2ib85vbYiea3jg==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.2.2" + "@babel/helper-define-polyfill-provider": "^0.3.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -5073,7 +5323,11 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", - "dev": true + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, "node_modules/balanced-match": { "version": "1.0.0", @@ -5111,44 +5365,6 @@ "node": ">=0.10.0" } }, - "node_modules/base/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/base64-arraybuffer": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz", @@ -5242,12 +5458,6 @@ "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", "dev": true }, - "node_modules/boundary": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/boundary/-/boundary-1.0.1.tgz", - "integrity": "sha1-TWfcJgLAzBbdm85+v4fpSCkPWBI=", - "dev": true - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5279,18 +5489,6 @@ "node": ">=0.10.0" } }, - "node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", @@ -5310,9 +5508,9 @@ } }, "node_modules/browser-fs-access": { - "version": "0.20.4", - "resolved": "https://registry.npmjs.org/browser-fs-access/-/browser-fs-access-0.20.4.tgz", - "integrity": "sha512-rSbY1AIoDe+fvYZ1LiRDdKBnytfsd1nN/GKS/DRZAhaJkz3cfbp14IHw5lk4FFWBelD6Sw6EtdnAI990ZuBZjg==" + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/browser-fs-access/-/browser-fs-access-0.23.0.tgz", + "integrity": "sha512-MMkxI9sHD5c//9qVFW8qM6qY9n/3PhLR6LhqMalJZK83O0/wrmzrzafy0JCGkaXvXcW5PC+Mq+A31DGoDkdQ9Q==" }, "node_modules/browser-pack": { "version": "6.1.0", @@ -5515,16 +5713,16 @@ } }, "node_modules/browserslist": { - "version": "4.16.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.8.tgz", - "integrity": "sha512-sc2m9ohR/49sWEbPj14ZSSZqp+kbi16aLao42Hmn3Z8FpjuMaq2xCA2l4zl9ITfyzvnvyE0hcg62YkIGKxgaNQ==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.18.1.tgz", + "integrity": "sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ==", "dev": true, "dependencies": { - "caniuse-lite": "^1.0.30001251", - "colorette": "^1.3.0", - "electron-to-chromium": "^1.3.811", + "caniuse-lite": "^1.0.30001280", + "electron-to-chromium": "^1.3.896", "escalade": "^3.1.1", - "node-releases": "^1.1.75" + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" }, "bin": { "browserslist": "cli.js" @@ -5767,6 +5965,16 @@ "node": "*" } }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, "node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -5819,9 +6027,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001251", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz", - "integrity": "sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A==", + "version": "1.0.30001284", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001284.tgz", + "integrity": "sha512-t28SKa7g6kiIQi6NHeOcKrOrGMzCRrXvlasPwWC26TH2QNdglgzQIRUuJ0cR3NeQPH+5jpuveeeSFDLm2zbkEw==", "dev": true, "funding": { "type": "opencollective", @@ -5829,19 +6037,21 @@ } }, "node_modules/canvg": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.7.tgz", - "integrity": "sha512-4sq6iL5Q4VOXS3PL1BapiXIZItpxYyANVzsAKpTPS5oq4u3SKbGfUcbZh2gdLCQ3jWpG/y5wRkMlBBAJhXeiZA==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.9.tgz", + "integrity": "sha512-rDXcnRPuz4QHoCilMeoTxql+fvGqNAxp+qV/KHD8rOiJSAfVjFclbdUNHD2Uqfthr+VMg17bD2bVuk6F07oLGw==", "dependencies": { - "@babel/runtime-corejs3": "^7.9.6", + "@babel/runtime": "^7.12.5", "@types/raf": "^3.4.0", + "core-js": "^3.8.3", "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", "rgbcolor": "^1.0.1", "stackblur-canvas": "^2.0.0", - "svg-pathdata": "^5.0.5" + "svg-pathdata": "^6.0.3" }, "engines": { - "node": ">=8.0.0" + "node": ">=10.0.0" } }, "node_modules/caseless": { @@ -5862,6 +6072,16 @@ "node": ">= 10" } }, + "node_modules/ccount": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", + "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -5907,6 +6127,7 @@ "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", "dev": true, "dependencies": { "anymatch": "^2.0.0", @@ -5971,6 +6192,98 @@ "node": ">=0.10.0" } }, + "node_modules/class-utils/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -6093,12 +6406,6 @@ "node": ">=0.8.0" } }, - "node_modules/collapse-white-space": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", - "dev": true - }, "node_modules/collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -6196,15 +6503,6 @@ "node": ">= 6" } }, - "node_modules/comment-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.2.4.tgz", - "integrity": "sha512-pm0b+qv+CkWNriSTMsfnjChF9kH0kxz55y44Wo5le9qLxMj5xDQAaEd9ZN1ovSuk9CsrncWaFwgpOMg7ClJwkw==", - "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", @@ -6470,9 +6768,9 @@ } }, "node_modules/core-js": { - "version": "3.16.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.3.tgz", - "integrity": "sha512-lM3GftxzHNtPNUJg0v4pC2RC6puwMd6VZA7vXUczi+SKmCWSf4JwO89VJGMqbzmB7jlK7B5hr3S64PqwFL49cA==", + "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", @@ -6480,9 +6778,9 @@ } }, "node_modules/core-js-bundle": { - "version": "3.16.3", - "resolved": "https://registry.npmjs.org/core-js-bundle/-/core-js-bundle-3.16.3.tgz", - "integrity": "sha512-h2AiKHbsoj0RwI4mQqteOhdYxeKClV8QK0LoB92QDaggKgkQ+PSQyLGu0uV8bhXdyuPKB9VvdcCJa6k7OSlo5w==", + "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": { @@ -6491,12 +6789,12 @@ } }, "node_modules/core-js-compat": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.16.0.tgz", - "integrity": "sha512-5D9sPHCdewoUK7pSUPfTF7ZhLh8k9/CoJXWUEo+F1dZT5Z1DVgcuRqUKhjeKW+YLb8f21rTFgWwQJiNw1hoZ5Q==", + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.19.2.tgz", + "integrity": "sha512-ObBY1W5vx/LFFMaL1P5Udo4Npib6fu+cMokeziWkA8Tns4FcDemKF5j9JvaI5JhdkW8EQJQGJN1EcrzmEwuAqQ==", "dev": true, "dependencies": { - "browserslist": "^4.16.6", + "browserslist": "^4.18.1", "semver": "7.0.0" }, "funding": { @@ -6514,9 +6812,10 @@ } }, "node_modules/core-js-pure": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.16.0.tgz", - "integrity": "sha512-wzlhZNepF/QA9yvx3ePDgNGudU5KDB8lu/TRPKelYA/QtSnkS/cLl2W+TIdEX1FAFcBr0YpY7tPDlcmXJ7AyiQ==", + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.2.tgz", + "integrity": "sha512-5LkcgQEy8pFeVnd/zomkUBSwnmIxuF1C8E9KrMAbOc8f34IBT9RGvTYeNDdp1PnvMJrrVhvk1hg/yVV5h/znlg==", + "dev": true, "hasInstallScript": true, "funding": { "type": "opencollective", @@ -6862,20 +7161,20 @@ "dev": true }, "node_modules/cypress": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-8.3.1.tgz", - "integrity": "sha512-1v6pfx+/5cXhaT5T6QKOvnkawmEHWHLiVzm3MYMoQN1fkX2Ma1C32STd3jBStE9qT5qPSTILjGzypVRxCBi40g==", + "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": { - "@cypress/request": "^2.88.6", + "@cypress/request": "^2.88.10", "@cypress/xvfb": "^1.2.4", "@types/node": "^14.14.31", "@types/sinonjs__fake-timers": "^6.0.2", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", "blob-util": "^2.0.2", - "bluebird": "^3.7.2", + "bluebird": "3.7.2", "cachedir": "^2.3.0", "chalk": "^4.1.0", "check-more-types": "^2.24.0", @@ -6902,7 +7201,7 @@ "minimist": "^1.2.5", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", - "ramda": "~0.27.1", + "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", "supports-color": "^8.1.1", "tmp": "~0.2.1", @@ -6917,19 +7216,6 @@ "node": ">=12.0.0" } }, - "node_modules/cypress-axe": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/cypress-axe/-/cypress-axe-0.13.0.tgz", - "integrity": "sha512-fCIy7RiDCm7t30U3C99gGwQrUO307EYE1QqXNaf9ToK4DVqW8y5on+0a/kUHMrHdlls2rENF6TN9ZPpPpwLrnw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "axe-core": "^3 || ^4", - "cypress": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, "node_modules/cypress-multi-reporters": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/cypress-multi-reporters/-/cypress-multi-reporters-1.5.0.tgz", @@ -7198,15 +7484,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/cypress/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/dash-ast": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", @@ -7240,9 +7517,9 @@ } }, "node_modules/dayjs": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.6.tgz", - "integrity": "sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", + "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==", "dev": true }, "node_modules/debounce": { @@ -7382,44 +7659,6 @@ "node": ">=0.10.0" } }, - "node_modules/define-property/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", @@ -7637,28 +7876,11 @@ "node": ">=8" } }, - "node_modules/domhandler": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", - "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", - "dev": true, - "dependencies": { - "domelementtype": "^2.1.0" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/domhandler/node_modules/domelementtype": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", - "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==", - "dev": true - }, "node_modules/dompurify": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.2.6.tgz", - "integrity": "sha512-7b7ZArhhH0SP6W2R9cqK6RjaU82FZ2UPM7RO8qN1b1wyvC/NY1FNWcX1Pu00fFOAnzEORtwXe4bPaClg6pUybQ==" + "integrity": "sha512-7b7ZArhhH0SP6W2R9cqK6RjaU82FZ2UPM7RO8qN1b1wyvC/NY1FNWcX1Pu00fFOAnzEORtwXe4bPaClg6pUybQ==", + "devOptional": true }, "node_modules/duplexer": { "version": "0.1.1", @@ -7692,15 +7914,15 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.3.822", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.822.tgz", - "integrity": "sha512-k7jG5oYYHxF4jx6PcqwHX3JVME/OjzolqOZiIogi9xtsfsmTjTdie4x88OakYFPEa8euciTgCCzvVNwvmjHb1Q==", + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.11.tgz", + "integrity": "sha512-2OhsaYgsWGhWjx2et8kaUcdktPbBGjKM2X0BReUCKcSCPttEY+hz2zie820JLbttU8jwL92+JJysWwkut3wZgA==", "dev": true }, "node_modules/elix": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/elix/-/elix-15.0.0.tgz", - "integrity": "sha512-Va7hBkoR/tEdn8v8JD6gdgxm4fd5JRLlLCpxMLd9OyLUps+vEesa19YuziPstWy3bexu7+Z3dxhWOeKX11zkHg==" + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/elix/-/elix-15.0.1.tgz", + "integrity": "sha512-hgL6EDdMO/JBJLmDfaM8AL0f3zQXDIwkjQEhaLi9OTLV+3q445ErkBZuHGK9UzAoIq3I062ldDXRX48l1vfqCg==" }, "node_modules/elliptic": { "version": "6.5.3", @@ -7910,22 +8132,25 @@ } }, "node_modules/es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-symbols": "^1.0.2", "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", + "is-callable": "^1.2.4", "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", "object-inspect": "^1.11.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", @@ -7941,9 +8166,9 @@ } }, "node_modules/es-module-lexer": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.7.1.tgz", - "integrity": "sha512-MgtWFl5No+4S3TmhDmCz2ObFGm6lEpTnzbQi+Dd+pw4mlTIZTmM2iAs5gRlmx5zS9luzobCSBSI90JM/1/JgOw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, "node_modules/es-to-primitive": { @@ -8023,32 +8248,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", @@ -8056,7 +8278,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", @@ -8065,7 +8287,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" }, @@ -8105,6 +8327,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", @@ -8131,12 +8377,13 @@ "dev": true }, "node_modules/eslint-module-utils": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz", - "integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", + "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", "dev": true, "dependencies": { "debug": "^3.2.7", + "find-up": "^2.1.0", "pkg-dir": "^2.0.0" }, "engines": { @@ -8228,211 +8475,24 @@ "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": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-chai-expect/-/eslint-plugin-chai-expect-2.2.0.tgz", - "integrity": "sha512-ExTJKhgeYMfY8wDj3UiZmgpMKJOUHGNHmWMlxT49JUDB1vTnw0sSNfXJSxnX+LcebyBD/gudXzjzD136WqPJrQ==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "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": "3.13.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-3.13.0.tgz", - "integrity": "sha512-cv8IYMuTXm7PIjMVDN2y4k/KVnKZmoNGHNq27/9dLstOLydKblieIv+oe2BN2WthuXnFNhaNvv3N1Bvl4dbIGA==", - "dev": true, - "dependencies": { - "@mdn/browser-compat-data": "^3.3.14", - "ast-metadata-inferer": "^0.7.0", - "browserslist": "^4.16.8", - "caniuse-lite": "^1.0.30001251", - "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" - } - }, - "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.11.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.11.3.tgz", - "integrity": "sha512-hOoAid+XNFtpvOzZSNWP5LDrQBEJwbZwjib4XJ1KcRYKjeVj0mAmPmucG4Egli4j/aruv+Ow/acacoloWWCl9Q==", - "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.1.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-6.1.2.tgz", - "integrity": "sha512-bhBIRyZFqI4EoF12lGDHAmgfff8eLXx6R52/K3ESQhsxzCzIE6hdebS7Py651f7U3RBotqroUnC3L29bR7qJWQ==", - "dev": true, - "dependencies": { - "htmlparser2": "^6.0.1" - } - }, "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==", + "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.3", - "array.prototype.flat": "^1.2.4", + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", "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", + "eslint-module-utils": "^2.7.1", "has": "^1.0.3", - "is-core-module": "^2.6.0", + "is-core-module": "^2.8.0", + "is-glob": "^4.0.3", "minimatch": "^3.0.4", - "object.values": "^1.1.4", - "pkg-up": "^2.0.0", - "read-pkg-up": "^3.0.0", + "object.values": "^1.1.5", "resolve": "^1.20.0", "tsconfig-paths": "^3.11.0" }, @@ -8440,7 +8500,7 @@ "node": ">=4" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { @@ -8448,6 +8508,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" }, @@ -8455,164 +8516,6 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/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/eslint-plugin-import/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/eslint-plugin-import/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/eslint-plugin-import/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/eslint-plugin-import/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/eslint-plugin-jsdoc": { - "version": "36.0.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-36.0.8.tgz", - "integrity": "sha512-brNjHvRuBy5CaV01mSp6WljrO/T8fHNj0DXG38odOGDnhI7HdcbLKX7DpSvg2Rfcifwh8GlnNFzx13sI05t3bg==", - "dev": true, - "dependencies": { - "@es-joy/jsdoccomment": "0.10.8", - "comment-parser": "1.2.4", - "debug": "^4.3.2", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "^1.1.1", - "lodash": "^4.17.21", - "regextras": "^0.8.0", - "semver": "^7.3.5", - "spdx-expression-parse": "^3.0.1" - }, - "engines": { - "node": "^12 || ^14 || ^16" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0" - } - }, - "node_modules/eslint-plugin-jsdoc/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/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.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-2.2.0.tgz", - "integrity": "sha512-Ctuc7aP1tU92qnFwVO1wDLEzf1jqMxwRkcSTw7gjbvnEqfh5CKUcTXM0sxg8CB2KDXrqpTuMZPgJ1XE9Olr7KA==", - "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": "3.1.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-3.1.5.tgz", - "integrity": "sha512-s/6w++p1590h/H/dE2Wo660bOkaM/3OEK14Y7xm1UT0bafxkKw1Cq0ksjxkxLdH/WWd014DlsLKuD6CyNrR2Dw==", - "dev": true, - "peerDependencies": { - "eslint": "^5 || ^6 || ^7" - } - }, - "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", @@ -8643,27 +8546,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", @@ -8674,22 +8556,106 @@ } }, "node_modules/eslint-plugin-promise": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.0.tgz", - "integrity": "sha512-NGmI6BH5L12pl7ScQHbg7tvtk4wPxxj8yPHH47NvSmMtFneC077PSeY3huFj06ZWZvtbfxSPt3RuOQD5XcR4ng==", + "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", @@ -8700,15 +8666,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", @@ -8753,116 +8710,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", @@ -8876,15 +8748,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": { @@ -8905,19 +8780,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", @@ -8963,24 +8825,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", @@ -8996,15 +8840,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", @@ -9029,13 +8864,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": { @@ -9072,6 +8912,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", @@ -9221,18 +9082,77 @@ "node": ">=0.10.0" } }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "dependencies": { - "is-extendable": "^0.1.0" + "kind-of": "^3.0.2" }, "engines": { "node": ">=0.10.0" } }, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -9240,25 +9160,12 @@ "dev": true }, "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend-shallow/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" + "is-extendable": "^0.1.0" }, "engines": { "node": ">=0.10.0" @@ -9295,56 +9202,6 @@ "node": ">=0.10.0" } }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -9404,17 +9261,16 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" }, "engines": { "node": ">=8" @@ -9445,9 +9301,9 @@ } }, "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "dependencies": { "is-glob": "^4.0.1" @@ -9466,16 +9322,16 @@ } }, "node_modules/fast-glob/node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "dependencies": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" }, "engines": { - "node": ">=8" + "node": ">=8.6" } }, "node_modules/fast-glob/node_modules/to-regex-range": { @@ -9524,6 +9380,10 @@ "dev": true, "dependencies": { "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/fd-slicer": { @@ -9612,18 +9472,6 @@ "node": ">=0.10.0" } }, - "node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/find-cache-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", @@ -9725,6 +9573,12 @@ "node": ">=0.10.0" } }, + "node_modules/foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, "node_modules/foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -9857,6 +9711,7 @@ "version": "1.2.13", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", "dev": true, "hasInstallScript": true, "optional": true, @@ -9993,15 +9848,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", @@ -10026,6 +9872,22 @@ "node": ">=8" } }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -10399,7 +10261,6 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, - "peer": true, "bin": { "he": "bin/he" } @@ -10461,10 +10322,37 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dev": true, + "dependencies": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "bin": { + "html-minifier": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/html-minifier/node_modules/commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + }, "node_modules/html2canvas": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.3.2.tgz", - "integrity": "sha512-4+zqv87/a1LsaCrINV69wVLGG8GBZcYBboz1JPWEgiXcWoD9kroLzccsBRU/L9UlfV2MAZ+3J92U9IQPVMDeSQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.3.4.tgz", + "integrity": "sha512-81pWiqkzRVu5ap/IEd4g+YDAZu3ozTFvJxnlRfrRVQ4JK4A1optD6Qu4YhGF2HdPZXzt89KwUi1C9TmH1O8Etg==", "dependencies": { "css-line-break": "2.0.1", "text-segmentation": "^1.0.2" @@ -10482,81 +10370,19 @@ "node": ">=0.10" } }, - "node_modules/htmlparser2": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.0.1.tgz", - "integrity": "sha512-GDKPd+vk4jvSuvCbyuzx/unmXkk090Azec7LovXP8as1Hn8q9p3hbjmDGbUqqhknw0ajwit6LiiWqfiTUPMK7w==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.4.4", - "entities": "^2.0.0" - } - }, - "node_modules/htmlparser2/node_modules/dom-serializer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", - "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "entities": "^2.0.0" - } - }, - "node_modules/htmlparser2/node_modules/domelementtype": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", - "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==", - "dev": true - }, - "node_modules/htmlparser2/node_modules/domutils": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.4.tgz", - "integrity": "sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0" - } - }, "node_modules/http-assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.4.1.tgz", - "integrity": "sha512-rdw7q6GTlibqVVbXr0CKelfV5iY8G2HqEUkhSk297BMbSpSL8crXC+9rjKoMcZZEsksX30le6f/4ul4E28gegw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz", + "integrity": "sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==", "dev": true, "dependencies": { "deep-equal": "~1.0.1", - "http-errors": "~1.7.2" + "http-errors": "~1.8.0" }, "engines": { "node": ">= 0.8" } }, - "node_modules/http-assert/node_modules/http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/http-assert/node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "dev": true - }, "node_modules/http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -10564,16 +10390,16 @@ "dev": true }, "node_modules/http-errors": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.0.tgz", - "integrity": "sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dev": true, "dependencies": { "depd": "~1.1.2", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" }, "engines": { "node": ">= 0.6" @@ -10682,9 +10508,9 @@ } }, "node_modules/i18next": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-20.4.0.tgz", - "integrity": "sha512-89iWWJudmaHJwzIdJ/1eu98GtsJnwBhOUWwlAre70itPMuTE/NTPtgVeaS1CGaB8Q3XrYBGpEqlq4jsScDx9kg==", + "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" } @@ -10751,6 +10577,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", @@ -10918,24 +10769,12 @@ } }, "node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" + "kind-of": "^6.0.0" }, "engines": { "node": ">=0.10.0" @@ -10957,6 +10796,22 @@ "is-decimal": "^1.0.0" } }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -11006,9 +10861,9 @@ "dev": true }, "node_modules/is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true, "engines": { "node": ">= 0.4" @@ -11018,9 +10873,9 @@ } }, "node_modules/is-core-module": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", - "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -11030,24 +10885,12 @@ } }, "node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" + "kind-of": "^6.0.0" }, "engines": { "node": ">=0.10.0" @@ -11069,28 +10912,19 @@ "dev": true }, "node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-docker": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", @@ -11160,20 +10994,10 @@ "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.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { "is-extglob": "^2.1.1" @@ -11188,15 +11012,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", @@ -11257,16 +11072,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", @@ -11312,16 +11117,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", @@ -11347,6 +11142,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -11383,6 +11187,25 @@ "node": ">= 0.4" } }, + "node_modules/is-typed-array": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", + "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.5", + "foreach": "^2.0.5", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -11401,11 +11224,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-whitespace-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", - "dev": true + "node_modules/is-weakref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", + "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/is-windows": { "version": "1.0.2", @@ -11416,12 +11245,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-word-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", - "dev": true - }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -11762,15 +11585,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", @@ -11827,15 +11641,6 @@ "node": ">=8.15.0" } }, - "node_modules/jsdoc-type-pratt-parser": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-1.1.1.tgz", - "integrity": "sha512-uelRmpghNwPBuZScwgBG/OzodaFk5RbO5xaivBdsAY70icWfShwZ7PCMO0x1zSkOa8T1FzHThmrdoyg/0AwV5g==", - "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", @@ -11863,15 +11668,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", @@ -11991,15 +11787,6 @@ "universalify": "^2.0.0" } }, - "node_modules/jsonfile/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", @@ -12032,18 +11819,19 @@ } }, "node_modules/jspdf": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.3.1.tgz", - "integrity": "sha512-1vp0USP1mQi1h7NKpwxjFgQkJ5ncZvtH858aLpycUc/M+r/RpWJT8PixAU7Cw/3fPd4fpC8eB/Bj42LnsR21YQ==", + "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", "btoa": "^1.2.1", - "canvg": "^3.0.6", - "core-js": "^3.6.0", - "dompurify": "^2.2.0", "fflate": "^0.4.8" }, "optionalDependencies": { + "canvg": "^3.0.6", + "core-js": "^3.6.0", + "dompurify": "^2.2.0", "html2canvas": "^1.0.0-rc.5" } }, @@ -12062,6 +11850,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", @@ -12093,9 +11894,9 @@ } }, "node_modules/koa": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.1.tgz", - "integrity": "sha512-Lb2Dloc72auj5vK4X4qqL7B5jyDPQaZucc9sR/71byg7ryoD1NCaCm63CShk9ID9quQvDEi1bGR/iGjCG7As3w==", + "version": "2.13.4", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.4.tgz", + "integrity": "sha512-43zkIKubNbnrULWlHdN5h1g3SEKXOEzoAlRsHOTFpnlDu8JlAOZSMJBLULusuXRequboiwJcj5vtYXKB3k7+2g==", "dev": true, "dependencies": { "accepts": "^1.3.5", @@ -12103,7 +11904,7 @@ "content-disposition": "~0.5.2", "content-type": "^1.0.4", "cookies": "~0.8.0", - "debug": "~3.1.0", + "debug": "^4.3.2", "delegates": "^1.0.0", "depd": "^2.0.0", "destroy": "^1.0.4", @@ -12114,7 +11915,7 @@ "http-errors": "^1.6.3", "is-generator-function": "^1.0.7", "koa-compose": "^4.1.0", - "koa-convert": "^1.2.0", + "koa-convert": "^2.0.0", "on-finished": "^2.3.0", "only": "~0.0.2", "parseurl": "^1.3.2", @@ -12133,25 +11934,16 @@ "dev": true }, "node_modules/koa-convert": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-1.2.0.tgz", - "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-2.0.0.tgz", + "integrity": "sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==", "dev": true, "dependencies": { "co": "^4.6.0", - "koa-compose": "^3.0.0" + "koa-compose": "^4.1.0" }, "engines": { - "node": ">= 4" - } - }, - "node_modules/koa-convert/node_modules/koa-compose": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", - "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", - "dev": true, - "dependencies": { - "any-promise": "^1.1.0" + "node": ">= 10" } }, "node_modules/koa-etag": { @@ -12178,9 +11970,9 @@ } }, "node_modules/koa-send/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" @@ -12229,12 +12021,20 @@ "dev": true }, "node_modules/koa/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "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.0.0" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/koa/node_modules/depd": { @@ -12246,6 +12046,12 @@ "node": ">= 0.8" } }, + "node_modules/koa/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/labeled-stream-splicer": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", @@ -12526,12 +12332,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", @@ -12720,14 +12520,11 @@ "loose-envify": "cli.js" } }, - "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/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true }, "node_modules/lru-cache": { "version": "6.0.0", @@ -12839,12 +12636,6 @@ "node": ">=0.10.0" } }, - "node_modules/markdown-escapes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", - "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", - "dev": true - }, "node_modules/markdown-it": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", @@ -12867,6 +12658,19 @@ "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", "dev": true }, + "node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "dev": true, + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/marked": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.3.tgz", @@ -12890,6 +12694,95 @@ "safe-buffer": "^5.1.2" } }, + "node_modules/mdast-util-find-and-replace": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-1.1.1.tgz", + "integrity": "sha512-9cKl33Y21lyckGzpSmEQnIDjEfeeWelN5s1kUW1LwdB0Fkuq2u+4GdqcGEygYxJE8GVqCl0741bYXHgamfWAZA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^4.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/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/mdast-util-footnote": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/mdast-util-footnote/-/mdast-util-footnote-0.1.7.tgz", + "integrity": "sha512-QxNdO8qSxqbO2e3m09KwDKfWiLgqyCurdWTQ198NpbZ2hxntdc+VKS4fDJCmNWbAroUdYnSthu+XbZ8ovh8C3w==", + "dev": true, + "dependencies": { + "mdast-util-to-markdown": "^0.6.0", + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-footnote/node_modules/longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-footnote/node_modules/mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-footnote/node_modules/mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-footnote/node_modules/zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/mdast-util-from-markdown": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", @@ -12917,33 +12810,283 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-from-markdown/node_modules/parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "node_modules/mdast-util-frontmatter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-0.2.0.tgz", + "integrity": "sha512-FHKL4w4S5fdt1KjJCwB0178WJ0evnyyQr5kXTM3wrOVpytD0hrkvd+AOOjU9Td8onOejCkmZ+HQRT3CZ3coHHQ==", "dev": true, "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - } - }, - "node_modules/mdast-util-from-markdown/node_modules/unist-util-stringify-position": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", - "dev": true, - "dependencies": { - "@types/unist": "^2.0.2" + "micromark-extension-frontmatter": "^0.2.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, + "node_modules/mdast-util-gfm": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-0.1.2.tgz", + "integrity": "sha512-NNkhDx/qYcuOWB7xHUGWZYVXvjPFFd6afg6/e2g+SV4r9q5XUcCbV4Wfa3DLYIiD+xAEZc6K4MGaE/m0KDcPwQ==", + "dev": true, + "dependencies": { + "mdast-util-gfm-autolink-literal": "^0.1.0", + "mdast-util-gfm-strikethrough": "^0.2.0", + "mdast-util-gfm-table": "^0.1.0", + "mdast-util-gfm-task-list-item": "^0.1.0", + "mdast-util-to-markdown": "^0.6.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-0.1.3.tgz", + "integrity": "sha512-GjmLjWrXg1wqMIO9+ZsRik/s7PLwTaeCHVB7vRxUwLntZc8mzmTsLVr6HW1yLokcnhfURsn5zmSVdi3/xWWu1A==", + "dev": true, + "dependencies": { + "ccount": "^1.0.0", + "mdast-util-find-and-replace": "^1.1.0", + "micromark": "^2.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-0.2.3.tgz", + "integrity": "sha512-5OQLXpt6qdbttcDG/UxYY7Yjj3e8P7X16LzvpX8pIQPYJ/C2Z1qFGMmcw+1PZMUM3Z8wt8NRfYTvCni93mgsgA==", + "dev": true, + "dependencies": { + "mdast-util-to-markdown": "^0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough/node_modules/longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm-strikethrough/node_modules/mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough/node_modules/mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough/node_modules/zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-0.1.6.tgz", + "integrity": "sha512-j4yDxQ66AJSBwGkbpFEp9uG/LS1tZV3P33fN1gkyRB2LoRL+RR3f76m0HPHaby6F4Z5xr9Fv1URmATlRRUIpRQ==", + "dev": true, + "dependencies": { + "markdown-table": "^2.0.0", + "mdast-util-to-markdown": "~0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table/node_modules/longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm-table/node_modules/mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table/node_modules/mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table/node_modules/zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-0.1.6.tgz", + "integrity": "sha512-/d51FFIfPsSmCIRNp7E6pozM9z1GYPIkSy1urQ8s/o4TC22BZ7DqfHFWiqBD23bc7J3vV1Fc9O4QIHBlfuit8A==", + "dev": true, + "dependencies": { + "mdast-util-to-markdown": "~0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item/node_modules/longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm-task-list-item/node_modules/mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item/node_modules/mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item/node_modules/zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm/node_modules/longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm/node_modules/mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm/node_modules/mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm/node_modules/zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/mdast-util-to-markdown": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.1.1.tgz", @@ -13492,6 +13635,112 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/micromark-extension-footnote": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/micromark-extension-footnote/-/micromark-extension-footnote-0.3.2.tgz", + "integrity": "sha512-gr/BeIxbIWQoUm02cIfK7mdMZ/fbroRpLsck4kvFtjbzP4yi+OPVbnukTc/zy0i7spC2xYE/dbX1Sur8BEDJsQ==", + "dev": true, + "dependencies": { + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-frontmatter": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-0.2.2.tgz", + "integrity": "sha512-q6nPLFCMTLtfsctAuS0Xh4vaolxSFUWUWR6PZSrXXiRy+SANGllpcqdXFv2z07l0Xz/6Hl40hK0ffNCJPH2n1A==", + "dev": true, + "dependencies": { + "fault": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-0.3.3.tgz", + "integrity": "sha512-oVN4zv5/tAIA+l3GbMi7lWeYpJ14oQyJ3uEim20ktYFAcfX1x3LNlFGGlmrZHt7u9YlKExmyJdDGaTt6cMSR/A==", + "dev": true, + "dependencies": { + "micromark": "~2.11.0", + "micromark-extension-gfm-autolink-literal": "~0.5.0", + "micromark-extension-gfm-strikethrough": "~0.6.5", + "micromark-extension-gfm-table": "~0.4.0", + "micromark-extension-gfm-tagfilter": "~0.3.0", + "micromark-extension-gfm-task-list-item": "~0.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-0.5.7.tgz", + "integrity": "sha512-ePiDGH0/lhcngCe8FtH4ARFoxKTUelMp4L7Gg2pujYD5CSMb9PbblnyL+AAMud/SNMyusbS2XDSiPIRcQoNFAw==", + "dev": true, + "dependencies": { + "micromark": "~2.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-0.6.5.tgz", + "integrity": "sha512-PpOKlgokpQRwUesRwWEp+fHjGGkZEejj83k9gU5iXCbDG+XBA92BqnRKYJdfqfkrRcZRgGuPuXb7DaK/DmxOhw==", + "dev": true, + "dependencies": { + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-0.4.3.tgz", + "integrity": "sha512-hVGvESPq0fk6ALWtomcwmgLvH8ZSVpcPjzi0AjPclB9FsVRgMtGZkUcpE0zgjOCFAznKepF4z3hX8z6e3HODdA==", + "dev": true, + "dependencies": { + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-0.3.0.tgz", + "integrity": "sha512-9GU0xBatryXifL//FJH+tAZ6i240xQuFrSL7mYi8f4oZSbc+NvXjkrHemeYP0+L4ZUT+Ptz3b95zhUZnMtoi/Q==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-0.3.3.tgz", + "integrity": "sha512-0zvM5iSLKrc/NQl84pZSjGo66aTGd57C1idmlWmE87lkMcXrTxg1uXa/nXomxJytoje9trP0NDLvw4bZ/Z/XCQ==", + "dev": true, + "dependencies": { + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/micromark-factory-destination": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", @@ -13864,24 +14113,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/micromark/node_modules/parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "dev": true, - "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -13906,6 +14137,31 @@ "node": ">=0.10.0" } }, + "node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", @@ -14166,6 +14422,12 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, "node_modules/mocha": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.0.3.tgz", @@ -14542,16 +14804,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", @@ -14677,12 +14929,18 @@ "dev": true }, "node_modules/nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", "dev": true, "optional": true }, + "node_modules/nanocolors": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/nanocolors/-/nanocolors-0.2.13.tgz", + "integrity": "sha512-0n3mSAQLPpGLV9ORXT5+C/D4mwew7Ebws69Hx4E2sgz2ZA5+32Q80B9tL8PbL7XHnRDiAxH/pnrUJ9a4fkTNTA==", + "dev": true + }, "node_modules/nanoid": { "version": "3.1.23", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", @@ -14718,6 +14976,31 @@ "node": ">=0.10.0" } }, + "node_modules/nanomatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -14739,6 +15022,15 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1" + } + }, "node_modules/node-gyp": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", @@ -14815,9 +15107,9 @@ } }, "node_modules/node-releases": { - "version": "1.1.75", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", "dev": true }, "node_modules/node-static": { @@ -15327,15 +15619,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", @@ -15377,6 +15660,53 @@ "node": ">=0.10.0" } }, + "node_modules/object-copy/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-copy/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -15437,6 +15767,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", @@ -15450,14 +15824,14 @@ } }, "node_modules/object.values": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" + "es-abstract": "^1.19.1" }, "engines": { "node": ">= 0.4" @@ -15532,9 +15906,9 @@ } }, "node_modules/open-cli": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/open-cli/-/open-cli-7.0.0.tgz", - "integrity": "sha512-VxL1HWSsufFSxdcOq5Ijkd1sjK7XnmCI1QF1bYk4va3JI2nl+wLTTgOZ4i1OyNljb9rLoqajtFNCl91DmiIkQw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/open-cli/-/open-cli-7.0.1.tgz", + "integrity": "sha512-w//Mb5nLGTu9aIAsAehgxV+CGEkd+P3CbdoTW8y2coQ/fmGXBSrea0i4RBqGnd9prSPX1akrBYc0e3NnWM4SPA==", "dev": true, "dependencies": { "file-type": "^16.5.0", @@ -15868,6 +16242,15 @@ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -15934,9 +16317,9 @@ } }, "node_modules/parse-entities": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz", - "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", "dev": true, "dependencies": { "character-entities": "^1.0.0", @@ -15945,6 +16328,10 @@ "is-alphanumerical": "^1.0.0", "is-decimal": "^1.0.0", "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/parse-headers": { @@ -16131,12 +16518,21 @@ "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==", "dev": true }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "engines": { "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/pidtree": { @@ -16184,6 +16580,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", @@ -16401,15 +16844,23 @@ "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": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "dev": true + }, "node_modules/ps-tree": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", @@ -16535,12 +16986,6 @@ "performance-now": "^2.1.0" } }, - "node_modules/ramda": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", - "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", - "dev": true - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -16560,6 +17005,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", @@ -16785,18 +17236,18 @@ } }, "node_modules/regenerate": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", - "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "dev": true }, "node_modules/regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", + "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", "dev": true, "dependencies": { - "regenerate": "^1.4.0" + "regenerate": "^1.4.2" }, "engines": { "node": ">=4" @@ -16830,32 +17281,76 @@ "node": ">=0.10.0" } }, - "node_modules/regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "dependencies": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "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", + "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^9.0.0", + "regjsgen": "^0.5.2", + "regjsparser": "^0.7.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" }, "engines": { "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", @@ -16863,9 +17358,9 @@ "dev": true }, "node_modules/regjsparser": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", - "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", + "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", "dev": true, "dependencies": { "jsesc": "~0.5.0" @@ -16883,6 +17378,15 @@ "jsesc": "bin/jsesc" } }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", @@ -16912,9 +17416,9 @@ } }, "node_modules/remark-cli": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/remark-cli/-/remark-cli-10.0.0.tgz", - "integrity": "sha512-Yc5kLsJ5vgiQJl6xMLLJHqPac6OSAC5DOqKQrtmzJxSdJby2Jgr+OpIAkWQYwvbNHEspNagyoQnuwK2UCWg73g==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-cli/-/remark-cli-10.0.1.tgz", + "integrity": "sha512-+eln31zLE69JwBMoa8nd2sPC0DFZyiWgBrshL8aKb3L2XXTRMuEKWE/IAtNPYEtcktceAQw+OpmqVy8pAmGOwQ==", "dev": true, "dependencies": { "remark": "^14.0.0", @@ -16928,20 +17432,52 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-frontmatter": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-1.3.3.tgz", - "integrity": "sha512-fM5eZPBvu2pVNoq3ZPW22q+5Ativ1oLozq2qYt9I2oNyxiUd/tDl0iLLntEVAegpZIslPWg1brhcP1VsaSVUag==", + "node_modules/remark-footnotes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-3.0.0.tgz", + "integrity": "sha512-ZssAvH9FjGYlJ/PBVKdSmfyPc3Cz4rTWgZLI4iE/SX8Nt5l3o3oEjv3wwG5VD7xOjktzdwp5coac+kJV9l4jgg==", "dev": true, "dependencies": { - "fault": "^1.0.1", - "xtend": "^4.0.1" + "mdast-util-footnote": "^0.1.0", + "micromark-extension-footnote": "^0.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-frontmatter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-3.0.0.tgz", + "integrity": "sha512-mSuDd3svCHs+2PyO29h7iijIZx4plX0fheacJcAoYAASfgzgVIcXGYSq9GFyYocFLftQs8IOmmkgtOovs6d4oA==", + "dev": true, + "dependencies": { + "mdast-util-frontmatter": "^0.2.0", + "micromark-extension-frontmatter": "^0.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-1.0.0.tgz", + "integrity": "sha512-KfexHJCiqvrdBZVbQ6RopMZGwaXz6wFJEfByIuEwGf0arvITHjiKKZ1dpXujjH9KZdm1//XJQwgfnJ3lmXaDPA==", + "dev": true, + "dependencies": { + "mdast-util-gfm": "^0.1.0", + "micromark-extension-gfm": "^0.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/remark-lint-ordered-list-marker-value": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/remark-lint-ordered-list-marker-value/-/remark-lint-ordered-list-marker-value-3.0.1.tgz", - "integrity": "sha512-02tEsP+jKxZr7zhTVTbr6sThraTsUUKCmRdONBBwAFlK3bibZJYGMukjhR7rJtCbO/uHQqGX4VhEWPcOcCoaUg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/remark-lint-ordered-list-marker-value/-/remark-lint-ordered-list-marker-value-3.1.1.tgz", + "integrity": "sha512-+bQZbo+v/A8CuLrO71gobJuKR4/sfnPgWyEggSa+zq+LXPK1HiMDjap0Wr07uYgcUXsXIPh+HD/5J5by6JL+vg==", "dev": true, "dependencies": { "@types/mdast": "^3.0.0", @@ -17113,26 +17649,16 @@ } }, "node_modules/remark-parse": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz", - "integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz", + "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==", "dev": true, "dependencies": { - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^1.1.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^1.0.0", - "vfile-location": "^2.0.0", - "xtend": "^4.0.1" + "mdast-util-from-markdown": "^0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/remark-stringify": { @@ -17577,9 +18103,9 @@ "dev": true }, "node_modules/repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -17594,15 +18120,6 @@ "node": ">=0.10" } }, - "node_modules/replace-ext": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -17812,6 +18329,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", "dev": true }, "node_modules/restore-cursor": { @@ -17886,10 +18404,9 @@ } }, "node_modules/rollup": { - "version": "2.56.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.3.tgz", - "integrity": "sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg==", - "dev": true, + "version": "2.62.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.62.0.tgz", + "integrity": "sha512-cJEQq2gwB0GWMD3rYImefQTSjrPYaC6s4J9pYqnstVLJ1CHa/aZNVkD4Epuvg4iLeMA4KRiq7UM7awKK6j7jcw==", "bin": { "rollup": "dist/bin/rollup" }, @@ -18119,6 +18636,32 @@ "node": ">=10" } }, + "node_modules/rollup-plugin-html": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-html/-/rollup-plugin-html-0.2.1.tgz", + "integrity": "sha1-oYYuyoeuVLZ3aJ0NQTORHoImRj0=", + "dev": true, + "dependencies": { + "html-minifier": "^3.0.2", + "rollup-pluginutils": "^1.5.0" + } + }, + "node_modules/rollup-plugin-html/node_modules/estree-walker": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.2.1.tgz", + "integrity": "sha1-va/oCVOD2EFNXcLs9MkXO225QS4=", + "dev": true + }, + "node_modules/rollup-plugin-html/node_modules/rollup-pluginutils": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz", + "integrity": "sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg=", + "dev": true, + "dependencies": { + "estree-walker": "^0.2.1", + "minimatch": "^3.0.2" + } + }, "node_modules/rollup-plugin-inject": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", @@ -18146,12 +18689,14 @@ } }, "node_modules/rollup-plugin-polyfill-node": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-polyfill-node/-/rollup-plugin-polyfill-node-0.7.0.tgz", - "integrity": "sha512-iJLZDfvxcQh3SpC0OiYlZG9ik26aRM29hiC2sARbAPXYunB8rzW8GtVaWuJgiCtX1hNAo/OaYvVXfPp15fMs7g==", - "license": "MIT", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-polyfill-node/-/rollup-plugin-polyfill-node-0.8.0.tgz", + "integrity": "sha512-C4UeKedOmOBkB3FgR+z/v9kzRwV1Q/H8xWs1u1+CNe4XOV6hINfOrcO+TredKxYvopCmr+WKUSNsFUnD1RLHgQ==", "dependencies": { "@rollup/plugin-inject": "^4.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" } }, "node_modules/rollup-plugin-progress": { @@ -18213,7 +18758,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "optional": true, "os": [ "darwin" @@ -18351,18 +18895,6 @@ "node": ">=0.10.0" } }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -18577,44 +19109,6 @@ "node": ">=0.10.0" } }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", @@ -18651,18 +19145,77 @@ "node": ">=0.10.0" } }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "node_modules/snapdragon/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "dependencies": { - "is-extendable": "^0.1.0" + "kind-of": "^3.0.2" }, "engines": { "node": ">=0.10.0" } }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/socket.io": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz", @@ -18908,9 +19461,9 @@ } }, "node_modules/source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "dev": true }, "node_modules/sourcemap-codec": { @@ -19020,6 +19573,31 @@ "node": ">=0.10.0" } }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -19066,10 +19644,198 @@ "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.13.1", - "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.13.1.tgz", - "integrity": "sha512-wZjksmjG5scEHXmV/3HWzImxNzUgaNQ6W8kkqL2GbiOldM+nqiqh7niimlC9ZGNopTGj16kheWZnZtSWgdBZNQ==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.14.0.tgz", + "integrity": "sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw==", "dev": true, "dependencies": { "bluebird": "3.7.2", @@ -19162,12 +19928,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/state-toggle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", - "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==", - "dev": true - }, "node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -19193,6 +19953,77 @@ "node": ">=0.10.0" } }, + "node_modules/static-extend/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -19273,19 +20104,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", @@ -19326,12 +20176,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" @@ -19379,6 +20229,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", @@ -19396,15 +20258,6 @@ "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/structured-source": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-3.0.2.tgz", - "integrity": "sha1-3YAkJeD1PcSm56yjdSkBoczaevU=", - "dev": true, - "dependencies": { - "boundary": "^1.0.1" - } - }, "node_modules/subarg": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", @@ -19427,22 +20280,25 @@ } }, "node_modules/svg-pathdata": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-5.0.5.tgz", - "integrity": "sha512-TAAvLNSE3fEhyl/Da19JWfMAdhSXTYeviXsLSoDT1UM76ADj5ndwAPX1FKQEgB/gFMPavOy6tOqfalXKUiXrow==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", "engines": { - "node": ">=6.9.5" + "node": ">=12.0.0" } }, "node_modules/svg2pdf.js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/svg2pdf.js/-/svg2pdf.js-2.1.0.tgz", - "integrity": "sha512-jai/P6F1IsMcoVUx9Rlnua9YHzaIjo/2enxJ+Xb5e8/m3UF5YDsFSyqIbTVoUZXgmmSI5wZWAtEz1QY4XzSPew==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/svg2pdf.js/-/svg2pdf.js-2.2.0.tgz", + "integrity": "sha512-ZmBBTUHe3vIsSEiDyadaZp0q0x+EgE8JNk7AeJsrAGOGbMntBeCcI3G0VqfWk2KtDbRHe/XoQjuudfCxq5Utzw==", "dependencies": { "cssesc": "^3.0.0", "font-family-papandreou": "^0.2.0-patch1", "specificity": "^0.4.1", "svgpath": "^2.3.0" + }, + "peerDependencies": { + "jspdf": "^2.0.0" } }, "node_modules/svgpath": { @@ -19466,17 +20322,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" @@ -19516,9 +20371,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", @@ -19902,6 +20757,31 @@ "node": ">=0.10.0" } }, + "node_modules/to-regex/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/to-vfile": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-7.2.1.tgz", @@ -19983,9 +20863,9 @@ } }, "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, "engines": { "node": ">=0.6" @@ -20058,12 +20938,6 @@ "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", "dev": true }, - "node_modules/trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=", - "dev": true - }, "node_modules/trim-newlines": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.0.2.tgz", @@ -20076,17 +20950,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/trim-trailing-lines": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", - "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==", - "dev": true - }, "node_modules/trough": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", - "dev": true + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, "node_modules/truncate-utf8-bytes": { "version": "1.0.2", @@ -20233,6 +21105,37 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, + "node_modules/uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dev": true, + "dependencies": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uglify-js/node_modules/commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + }, + "node_modules/uglify-js/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/umd": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", @@ -20279,51 +21182,41 @@ "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", "dev": true }, - "node_modules/unherit": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", - "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.0", - "xtend": "^4.0.0" - } - }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "dependencies": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" }, "engines": { "node": ">=4" } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true, "engines": { "node": ">=4" @@ -20348,17 +21241,21 @@ } }, "node_modules/unified": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz", - "integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", + "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", "dev": true, "dependencies": { "bail": "^1.0.0", "extend": "^3.0.0", - "is-plain-obj": "^1.1.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", "trough": "^1.0.0", - "vfile": "^2.0.0", - "x-is-string": "^0.1.0" + "vfile": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/unified-args": { @@ -20962,6 +21859,38 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unified/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "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" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/unified/node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", @@ -21031,10 +21960,14 @@ } }, "node_modules/unist-util-is": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", - "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, "node_modules/unist-util-position": { "version": "4.0.1", @@ -21046,43 +21979,37 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-remove-position": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz", - "integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==", - "dev": true, - "dependencies": { - "unist-util-visit": "^1.1.0" - } - }, "node_modules/unist-util-stringify-position": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz", - "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==", - "dev": true - }, - "node_modules/unist-util-visit": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", - "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", "dev": true, "dependencies": { - "unist-util-visit-parents": "^2.0.0" + "@types/unist": "^2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/unist-util-visit-parents": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", - "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", "dev": true, "dependencies": { - "unist-util-is": "^3.0.0" + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true, "engines": { "node": ">= 10.0.0" @@ -21155,6 +22082,12 @@ "yarn": "*" } }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, "node_modules/uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -21177,6 +22110,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", "dev": true }, "node_modules/url": { @@ -21314,30 +22248,33 @@ } }, "node_modules/vfile": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz", - "integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", "dev": true, "dependencies": { - "is-buffer": "^1.1.4", - "replace-ext": "1.0.0", - "unist-util-stringify-position": "^1.0.0", - "vfile-message": "^1.0.0" + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vfile-location": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz", - "integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA==", - "dev": true - }, "node_modules/vfile-message": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz", - "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", "dev": true, "dependencies": { - "unist-util-stringify-position": "^1.1.1" + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/vfile-reporter": { @@ -21542,6 +22479,29 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/vfile/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "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" + } + ], + "engines": { + "node": ">=4" + } + }, "node_modules/vlq": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", @@ -21708,6 +22668,26 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "node_modules/which-typed-array": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", + "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.5", + "foreach": "^2.0.5", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", @@ -21903,11 +22883,14 @@ } } }, - "node_modules/x-is-string": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", - "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", - "dev": true + "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", @@ -22171,35 +23154,35 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "requires": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" } }, "@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "version": "7.16.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz", + "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==", "dev": true }, "@babel/core": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz", - "integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz", + "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==", "dev": true, "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.0", - "@babel/helper-module-transforms": "^7.15.0", - "@babel/helpers": "^7.14.8", - "@babel/parser": "^7.15.0", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.7", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -22232,44 +23215,44 @@ } }, "@babel/generator": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", - "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.7.tgz", + "integrity": "sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg==", "dev": true, "requires": { - "@babel/types": "^7.15.0", + "@babel/types": "^7.16.7", "jsesc": "^2.5.1", "source-map": "^0.5.0" } }, "@babel/helper-annotate-as-pure": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz", - "integrity": "sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz", - "integrity": "sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-compilation-targets": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", - "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", "dev": true, "requires": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", "semver": "^6.3.0" }, "dependencies": { @@ -22282,33 +23265,34 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.8.tgz", - "integrity": "sha512-bpYvH8zJBWzeqi1o+co8qOrw+EXzQ/0c74gVmY205AWXy9nifHrOg77y+1zwxX5lXE7Icq4sPlSQ4O2kWBrteQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz", + "integrity": "sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-member-expression-to-functions": "^7.14.7", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", - "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.7.tgz", + "integrity": "sha512-fk5A6ymfp+O5+p2yCkXAu5Kyj6v0xh0RBeNcAkYUMDvvAAoxvSKXn+Jb37t/yWFiQVDFK1ELpUTD8/aLhCPu+g==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-annotate-as-pure": "^7.16.7", "regexpu-core": "^4.7.1" } }, "@babel/helper-define-polyfill-provider": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz", - "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.0.tgz", + "integrity": "sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg==", "dev": true, "requires": { "@babel/helper-compilation-targets": "^7.13.0", @@ -22322,9 +23306,9 @@ }, "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" @@ -22344,362 +23328,381 @@ } } }, - "@babel/helper-explode-assignable-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz", - "integrity": "sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ==", + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" } }, "@babel/helper-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", - "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-get-function-arity": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", - "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" } }, "@babel/helper-hoist-variables": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", - "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", - "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", + "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", "dev": true, "requires": { - "@babel/types": "^7.15.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-module-imports": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", - "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" } }, "@babel/helper-module-transforms": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", - "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", + "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.0", - "@babel/helper-simple-access": "^7.14.8", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-optimise-call-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", - "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" } }, "@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.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", "dev": true }, "@babel/helper-remap-async-to-generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz", - "integrity": "sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.7.tgz", + "integrity": "sha512-C3o117GnP/j/N2OWo+oepeWbFEKRfNaay+F1Eo5Mj3A1SRjyx+qaFhm23nlipub7Cjv2azdUUiDH+VlpdwUFRg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-wrap-function": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-replace-supers": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", - "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.15.0", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-simple-access": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", - "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", "dev": true, "requires": { - "@babel/types": "^7.14.8" + "@babel/types": "^7.16.7" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz", - "integrity": "sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.0" } }, "@babel/helper-split-export-declaration": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", - "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.16.7" } }, "@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", "dev": true }, "@babel/helper-wrap-function": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz", - "integrity": "sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.7.tgz", + "integrity": "sha512-7a9sABeVwcunnztZZ7WTgSw6jVYLzM1wua0Z4HIXm9S3/HC96WKQTkFgGEaj5W06SHHihPJ6Le6HzS5cGOQMNw==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helpers": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.8.tgz", - "integrity": "sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz", + "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==", "dev": true, "requires": { - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.8", - "@babel/types": "^7.14.8" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", + "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.0.tgz", - "integrity": "sha512-0v7oNOjr6YT9Z2RAOTv4T9aP+ubfx4Q/OhVtAet7PFDt0t9Oy6Jn+/rfC6b8HJ5zEqrQCiMxJfgtHpmIminmJQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz", + "integrity": "sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==", "dev": true }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz", - "integrity": "sha512-ZoJS2XCKPBfTmL122iP6NM9dOg+d4lc9fFk3zxc8iDjvt8Pk4+TlsHSKhIPf6X+L5ORCdBzqMZDjL/WHj7WknQ==", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", + "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", - "@babel/plugin-proposal-optional-chaining": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", + "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.7" } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.9.tgz", - "integrity": "sha512-d1lnh+ZnKrFKwtTYdw320+sQWCTwgkB9fmUhNXRADA4akR6wLjaruSGnIEUjpt9HCOwTr4ynFTKu19b7rFRpmw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.7.tgz", + "integrity": "sha512-TTXBT3A5c11eqRzaC6beO6rlFT3Mo9C2e8eB44tTr52ESXSK2CIc2fOp1ynpAwQA8HhBMho+WXhMHWlAe3xkpw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.7", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz", - "integrity": "sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", + "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-proposal-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.14.5.tgz", - "integrity": "sha512-KBAH5ksEnYHCegqseI5N9skTdxgJdmDoAOc0uXa+4QMYKeZD0w5IARh4FMlTNtaHhbB8v+KzMdTgxMMzsIy6Yg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", + "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz", - "integrity": "sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz", - "integrity": "sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", + "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz", - "integrity": "sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", + "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz", - "integrity": "sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", + "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz", - "integrity": "sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", + "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz", - "integrity": "sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz", - "integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz", + "integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==", "dev": true, "requires": { - "@babel/compat-data": "^7.14.7", - "@babel/helper-compilation-targets": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/compat-data": "^7.16.4", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.14.5" + "@babel/plugin-transform-parameters": "^7.16.7" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", - "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz", - "integrity": "sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", + "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-private-methods": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz", - "integrity": "sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.7.tgz", + "integrity": "sha512-7twV3pzhrRxSwHeIvFE6coPgvo+exNDOiGUMg39o2LiLo1Y+4aKpfkcLGcg1UHonzorCt7SNXnoMyCnnIOA8Sw==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-62EyfyA3WA0mZiF2e2IV9mc9Ghwxcg8YTu8BS4Wss4Y3PY725OmS9M0qLORbJwLqFtGh+jiE4wAmocK2CTUK2Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", + "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-create-class-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz", - "integrity": "sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", + "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-syntax-async-generators": { @@ -22757,12 +23760,12 @@ } }, "@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.0.tgz", + "integrity": "sha512-8zv2+xiPHwly31RK4RmnEYY5zziuF3O7W2kIDW+07ewWDh6Oi0dRq8kwvulRkFgt6DB97RlKs5c1y068iPlCUg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-syntax-logical-assignment-operators": { @@ -22838,367 +23841,376 @@ } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", - "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", + "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", - "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.7.tgz", + "integrity": "sha512-pFEfjnK4DfXCfAlA5I98BYdDJD8NltMzx19gt6DAmfE+2lXRfPUoa0/5SUjT4+TDE1W/rcxU/1lgN55vpAjjdg==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5" + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.7" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz", - "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.5.tgz", - "integrity": "sha512-LBYm4ZocNgoCqyxMLoOnwpsmQ18HWTQvql64t3GvMUzLQrNoV1BDG0lNftC8QKYERkZgCCT/7J5xWGObGAyHDw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", + "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-classes": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.9.tgz", - "integrity": "sha512-NfZpTcxU3foGWbl4wxmZ35mTsYJy8oQocbeIMoDAGGFarAmSQlL+LWMkDx/tj6pNotpbX3rltIA4dprgAPOq5A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", + "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz", - "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", + "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-destructuring": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", - "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", + "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz", - "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz", - "integrity": "sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", + "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", - "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-for-of": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz", - "integrity": "sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", + "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz", - "integrity": "sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz", - "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", + "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz", - "integrity": "sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz", - "integrity": "sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", + "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.0.tgz", - "integrity": "sha512-3H/R9s8cXcOGE8kgMlmjYYC9nqr5ELiPkJn4q0mypBrjhYQoc+5/Maq69vV4xRPWnkzZuwJPf5rArxpB/35Cig==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.7.tgz", + "integrity": "sha512-h2RP2kE7He1ZWKyAlanMZrAbdv+Acw1pA8dQZhE025WJZE2z0xzFADAinXA9fxd5bn7JnM+SdOGcndGx1ARs9w==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.15.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-simple-access": "^7.14.8", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.14.5.tgz", - "integrity": "sha512-mNMQdvBEE5DcMQaL5LbzXFMANrQjd2W7FPzg34Y4yEz7dBgdaC+9B84dSO+/1Wba98zoDbInctCDo4JGxz1VYA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", + "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz", - "integrity": "sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", + "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz", - "integrity": "sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.7.tgz", + "integrity": "sha512-kFy35VwmwIQwCjwrAQhl3+c/kr292i4KdLPKp5lPH03Ltc51qnFlIADoyPxc/6Naz3ok3WdYKg+KK6AH+D4utg==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7" } }, "@babel/plugin-transform-new-target": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz", - "integrity": "sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", + "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-object-super": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz", - "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" } }, "@babel/plugin-transform-parameters": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz", - "integrity": "sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", + "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-property-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz", - "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.0.tgz", + "integrity": "sha512-FJFdJAqaCpndL+pIf0aeD/qlQwT7QXOvR6Cc8JPvNhKJBi2zc/DPc4g05Y3fbD/0iWAMQFGij4+Xw+4L/BMpTg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5" } }, - "@babel/plugin-transform-react-display-name": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.1.tgz", - "integrity": "sha512-cAzB+UzBIrekfYxyLlFqf/OagTvHLcVBb5vpouzkYkBclRPraiygVnafvAoipErZLI8ANv8Ecn6E/m5qPXD26w==", + "@babel/plugin-transform-react-jsx": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.0.tgz", + "integrity": "sha512-rqDgIbukZ44pqq7NIRPGPGNklshPkvlmvqjdx3OZcGPk4zGIenYkxDTvl3LsSL8gqcc3ZzGmXPE6hR/u/voNOw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-annotate-as-pure": "^7.16.0", + "@babel/helper-module-imports": "^7.16.0", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-jsx": "^7.16.0", + "@babel/types": "^7.16.0" } }, - "@babel/plugin-transform-react-jsx": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.12.tgz", - "integrity": "sha512-JDWGuzGNWscYcq8oJVCtSE61a5+XAOos+V0HrxnDieUus4UMnBEosDnY1VJqU5iZ4pA04QY7l0+JvHL1hZEfsw==", + "@babel/plugin-transform-react-jsx-development": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.0.tgz", + "integrity": "sha512-qq65iSqBRq0Hr3wq57YG2AmW0H6wgTnIzpffTphrUWUgLCOK+zf1f7G0vuOiXrp7dU1qq+fQBoqZ3wCDAkhFzw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.12.10", - "@babel/helper-module-imports": "^7.12.5", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-jsx": "^7.12.1", - "@babel/types": "^7.12.12" + "@babel/plugin-transform-react-jsx": "^7.16.0" } }, "@babel/plugin-transform-react-jsx-self": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.12.1.tgz", - "integrity": "sha512-FbpL0ieNWiiBB5tCldX17EtXgmzeEZjFrix72rQYeq9X6nUK38HCaxexzVQrZWXanxKJPKVVIU37gFjEQYkPkA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.16.0.tgz", + "integrity": "sha512-97yCFY+2GvniqOThOSjPor8xUoDiQ0STVWAQMl3pjhJoFVe5DuXDLZCRSZxu9clx+oRCbTiXGgKEG/Yoyo6Y+w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-react-jsx-source": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.12.1.tgz", - "integrity": "sha512-keQ5kBfjJNRc6zZN1/nVHCd6LLIHq4aUKcVnvE/2l+ZZROSbqoiGFRtT5t3Is89XJxBQaP7NLZX2jgGHdZvvFQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.16.0.tgz", + "integrity": "sha512-8yvbGGrHOeb/oyPc9tzNoe9/lmIjz3HLa9Nc5dMGDyNpGjfFrk8D2KdEq9NRkftZzeoQEW6yPQ29TMZtrLiUUA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.0.tgz", + "integrity": "sha512-NC/Bj2MG+t8Ef5Pdpo34Ay74X4Rt804h5y81PwOpfPtmAK3i6CizmQqwyBQzIepz1Yt8wNr2Z2L7Lu3qBMfZMA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.0", + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-regenerator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz", - "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", + "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", "dev": true, "requires": { "regenerator-transform": "^0.14.2" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz", - "integrity": "sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", + "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz", - "integrity": "sha512-jIgkljDdq4RYDnJyQsiWbdvGeei/0MOTtSHKO/rfbd/mXBxNpdlulMx49L0HQ4pug1fXannxoqCI+fYSle9eSw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "resolve": "^1.8.1", - "semver": "^5.5.1" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz", - "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-spread": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz", - "integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", + "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz", - "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-template-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz", - "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", + "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz", - "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", + "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz", - "integrity": "sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz", - "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/polyfill": { @@ -23218,31 +24230,32 @@ } }, "@babel/preset-env": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.15.0.tgz", - "integrity": "sha512-FhEpCNFCcWW3iZLg0L2NPE9UerdtsCR6ZcsGHUX6Om6kbCQeL5QZDqFDmeNHC6/fy6UH3jEge7K4qG5uC9In0Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.7.tgz", + "integrity": "sha512-urX3Cee4aOZbRWOSa3mKPk0aqDikfILuo+C7qq7HY0InylGNZ1fekq9jmlr3pLWwZHF4yD7heQooc2Pow2KMyQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5", - "@babel/plugin-proposal-async-generator-functions": "^7.14.9", - "@babel/plugin-proposal-class-properties": "^7.14.5", - "@babel/plugin-proposal-class-static-block": "^7.14.5", - "@babel/plugin-proposal-dynamic-import": "^7.14.5", - "@babel/plugin-proposal-export-namespace-from": "^7.14.5", - "@babel/plugin-proposal-json-strings": "^7.14.5", - "@babel/plugin-proposal-logical-assignment-operators": "^7.14.5", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5", - "@babel/plugin-proposal-numeric-separator": "^7.14.5", - "@babel/plugin-proposal-object-rest-spread": "^7.14.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.14.5", - "@babel/plugin-proposal-optional-chaining": "^7.14.5", - "@babel/plugin-proposal-private-methods": "^7.14.5", - "@babel/plugin-proposal-private-property-in-object": "^7.14.5", - "@babel/plugin-proposal-unicode-property-regex": "^7.14.5", + "@babel/compat-data": "^7.16.4", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-async-generator-functions": "^7.16.7", + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-proposal-class-static-block": "^7.16.7", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.16.7", + "@babel/plugin-proposal-json-strings": "^7.16.7", + "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.16.7", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-private-methods": "^7.16.7", + "@babel/plugin-proposal-private-property-in-object": "^7.16.7", + "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", "@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", @@ -23257,44 +24270,44 @@ "@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.14.5", - "@babel/plugin-transform-async-to-generator": "^7.14.5", - "@babel/plugin-transform-block-scoped-functions": "^7.14.5", - "@babel/plugin-transform-block-scoping": "^7.14.5", - "@babel/plugin-transform-classes": "^7.14.9", - "@babel/plugin-transform-computed-properties": "^7.14.5", - "@babel/plugin-transform-destructuring": "^7.14.7", - "@babel/plugin-transform-dotall-regex": "^7.14.5", - "@babel/plugin-transform-duplicate-keys": "^7.14.5", - "@babel/plugin-transform-exponentiation-operator": "^7.14.5", - "@babel/plugin-transform-for-of": "^7.14.5", - "@babel/plugin-transform-function-name": "^7.14.5", - "@babel/plugin-transform-literals": "^7.14.5", - "@babel/plugin-transform-member-expression-literals": "^7.14.5", - "@babel/plugin-transform-modules-amd": "^7.14.5", - "@babel/plugin-transform-modules-commonjs": "^7.15.0", - "@babel/plugin-transform-modules-systemjs": "^7.14.5", - "@babel/plugin-transform-modules-umd": "^7.14.5", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.9", - "@babel/plugin-transform-new-target": "^7.14.5", - "@babel/plugin-transform-object-super": "^7.14.5", - "@babel/plugin-transform-parameters": "^7.14.5", - "@babel/plugin-transform-property-literals": "^7.14.5", - "@babel/plugin-transform-regenerator": "^7.14.5", - "@babel/plugin-transform-reserved-words": "^7.14.5", - "@babel/plugin-transform-shorthand-properties": "^7.14.5", - "@babel/plugin-transform-spread": "^7.14.6", - "@babel/plugin-transform-sticky-regex": "^7.14.5", - "@babel/plugin-transform-template-literals": "^7.14.5", - "@babel/plugin-transform-typeof-symbol": "^7.14.5", - "@babel/plugin-transform-unicode-escapes": "^7.14.5", - "@babel/plugin-transform-unicode-regex": "^7.14.5", - "@babel/preset-modules": "^0.1.4", - "@babel/types": "^7.15.0", - "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.2", - "babel-plugin-polyfill-regenerator": "^0.2.2", - "core-js-compat": "^3.16.0", + "@babel/plugin-transform-arrow-functions": "^7.16.7", + "@babel/plugin-transform-async-to-generator": "^7.16.7", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.16.7", + "@babel/plugin-transform-classes": "^7.16.7", + "@babel/plugin-transform-computed-properties": "^7.16.7", + "@babel/plugin-transform-destructuring": "^7.16.7", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.16.7", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.16.7", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.16.7", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.16.7", + "@babel/plugin-transform-modules-systemjs": "^7.16.7", + "@babel/plugin-transform-modules-umd": "^7.16.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.7", + "@babel/plugin-transform-new-target": "^7.16.7", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.16.7", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.16.7", + "@babel/plugin-transform-reserved-words": "^7.16.7", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.16.7", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.16.7", + "@babel/plugin-transform-typeof-symbol": "^7.16.7", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.16.7", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.4.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.19.1", "semver": "^6.3.0" }, "dependencies": { @@ -23307,9 +24320,9 @@ } }, "@babel/preset-modules": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -23319,23 +24332,10 @@ "esutils": "^2.0.2" } }, - "@babel/preset-react": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", - "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-transform-react-display-name": "^7.0.0", - "@babel/plugin-transform-react-jsx": "^7.0.0", - "@babel/plugin-transform-react-jsx-self": "^7.0.0", - "@babel/plugin-transform-react-jsx-source": "^7.0.0" - } - }, "@babel/register": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.15.3.tgz", - "integrity": "sha512-mj4IY1ZJkorClxKTImccn4T81+UKTo4Ux0+OFSV9hME1ooqS9UV+pJ6BjD0qXPK4T3XW/KNa79XByjeEMZz+fw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.16.7.tgz", + "integrity": "sha512-Ft+cuxorVxFj4RrPDs9TbJNE7ZbuJTyazUC6jLWRvBQT/qIDZPMe7MHgjlrA+11+XDLh+I0Pnx7sxPp4LRhzcA==", "dev": true, "requires": { "clone-deep": "^4.0.1", @@ -23346,46 +24346,48 @@ } }, "@babel/runtime": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz", - "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==", + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz", + "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==", "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/runtime-corejs3": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.15.3.tgz", - "integrity": "sha512-30A3lP+sRL6ml8uhoJSs+8jwpKzbw8CqBvDc1laeptxPm5FahumJxirigcbD2qTs71Sonvj1cyZB0OKGAmxQ+A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.7.tgz", + "integrity": "sha512-MiYR1yk8+TW/CpOD0CyX7ve9ffWTKqLk/L6pk8TPl0R8pNi+1pFY8fH9yET55KlvukQ4PAWfXsGr2YHVjcI4Pw==", + "dev": true, "requires": { - "core-js-pure": "^3.16.0", + "core-js-pure": "^3.19.0", "regenerator-runtime": "^0.13.4" } }, "@babel/template": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", - "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", "dev": true, "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/traverse": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", - "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.7.tgz", + "integrity": "sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.15.0", - "@babel/types": "^7.15.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -23408,206 +24410,425 @@ } }, "@babel/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", - "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz", + "integrity": "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" } }, "@cypress/browserify-preprocessor": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cypress/browserify-preprocessor/-/browserify-preprocessor-3.0.1.tgz", - "integrity": "sha512-sErmFSEr5287bLMRl0POGnyFtJCs/lSk5yxrUIJUIHZ8eDvtTEr0V93xRgLjJVG54gJU4MbpHy1mRPA9VZbtQA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@cypress/browserify-preprocessor/-/browserify-preprocessor-3.0.2.tgz", + "integrity": "sha512-y6mlFR+IR2cqcm3HabSp7AEcX9QfF1EUL4eOaw/7xexdhmdQU8ez6piyRopZQob4BK8oKTsc9PkupsU2rzjqMA==", "dev": true, "requires": { - "@babel/core": "7.4.5", - "@babel/plugin-proposal-class-properties": "7.3.0", - "@babel/plugin-proposal-object-rest-spread": "7.3.2", - "@babel/plugin-transform-runtime": "7.2.0", - "@babel/preset-env": "7.4.5", - "@babel/preset-react": "7.0.0", - "@babel/runtime": "7.3.1", - "babel-plugin-add-module-exports": "1.0.2", - "babelify": "10.0.0", - "bluebird": "3.5.3", - "browserify": "16.2.3", - "coffeeify": "3.0.1", - "coffeescript": "1.12.7", - "debug": "4.1.1", - "fs-extra": "9.0.0", - "lodash.clonedeep": "4.5.0", + "@babel/core": "^7.16.0", + "@babel/plugin-proposal-class-properties": "^7.16.0", + "@babel/plugin-proposal-object-rest-spread": "^7.16.0", + "@babel/plugin-transform-runtime": "^7.16.0", + "@babel/preset-env": "^7.16.0", + "@babel/preset-react": "^7.16.0", + "@babel/runtime": "^7.16.0", + "babel-plugin-add-module-exports": "^1.0.4", + "babelify": "^10.0.0", + "bluebird": "^3.7.2", + "browserify": "^16.2.3", + "coffeeify": "^3.0.1", + "coffeescript": "^1.12.7", + "debug": "^4.3.2", + "fs-extra": "^9.0.0", + "lodash.clonedeep": "^4.5.0", "through2": "^2.0.0", - "watchify": "3.11.1" + "watchify": "^4.0.0" }, "dependencies": { - "@babel/core": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.5.tgz", - "integrity": "sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==", + "@babel/plugin-transform-runtime": { + "version": "7.16.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.4.tgz", + "integrity": "sha512-pru6+yHANMTukMtEZGC4fs7XPwg35v8sj5CIEmE+gEkFljFiVJxEWxx/7ZDkTK+iZRYo1bFXBtfIN95+K3cJ5A==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.4", - "@babel/helpers": "^7.4.4", - "@babel/parser": "^7.4.5", - "@babel/template": "^7.4.4", - "@babel/traverse": "^7.4.5", - "@babel/types": "^7.4.4", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.11", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "@babel/helper-module-imports": "^7.16.0", + "@babel/helper-plugin-utils": "^7.14.5", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.4.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "semver": "^6.3.0" } }, - "@babel/plugin-proposal-class-properties": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.0.tgz", - "integrity": "sha512-wNHxLkEKTQ2ay0tnsam2z7fGZUi+05ziDJflEt3AZTP3oXLKHJp9HqhfroB/vdMvt3sda9fAbq7FsG8QPDrZBg==", + "@babel/preset-react": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.0.tgz", + "integrity": "sha512-d31IFW2bLRB28uL1WoElyro8RH5l6531XfxMtCeCmp6RVAF1uTfxxUA0LH1tXl+psZdwfmIbwoG4U5VwgbhtLw==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.3.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "@babel/plugin-transform-react-display-name": "^7.16.0", + "@babel/plugin-transform-react-jsx": "^7.16.0", + "@babel/plugin-transform-react-jsx-development": "^7.16.0", + "@babel/plugin-transform-react-pure-annotations": "^7.16.0" } }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.2.tgz", - "integrity": "sha512-DjeMS+J2+lpANkYLLO+m6GjoTMygYglKmRe6cDTbFv3L9i6mmiE8fe6B8MtCSLZpVXscD5kn7s6SgtHrDoBWoA==", + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, - "@babel/preset-env": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.5.tgz", - "integrity": "sha512-f2yNVXM+FsR5V8UwcFeIHzHWgnhXg3NpRmy0ADvALpnhB0SLbCvrCRr4BLOUYbQNLS+Z0Yer46x9dJXpXewI7w==", + "babel-plugin-add-module-exports": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-1.0.4.tgz", + "integrity": "sha512-g+8yxHUZ60RcyaUpfNzy56OtWW+x9cyEe9j+CranqLiqbju2yf/Cy6ZtYK40EZxtrdHllzlVZgLmcOUCTlJ7Jg==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.2.0", - "@babel/plugin-proposal-json-strings": "^7.2.0", - "@babel/plugin-proposal-object-rest-spread": "^7.4.4", - "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-syntax-async-generators": "^7.2.0", - "@babel/plugin-syntax-json-strings": "^7.2.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", - "@babel/plugin-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.4.4", - "@babel/plugin-transform-block-scoped-functions": "^7.2.0", - "@babel/plugin-transform-block-scoping": "^7.4.4", - "@babel/plugin-transform-classes": "^7.4.4", - "@babel/plugin-transform-computed-properties": "^7.2.0", - "@babel/plugin-transform-destructuring": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/plugin-transform-duplicate-keys": "^7.2.0", - "@babel/plugin-transform-exponentiation-operator": "^7.2.0", - "@babel/plugin-transform-for-of": "^7.4.4", - "@babel/plugin-transform-function-name": "^7.4.4", - "@babel/plugin-transform-literals": "^7.2.0", - "@babel/plugin-transform-member-expression-literals": "^7.2.0", - "@babel/plugin-transform-modules-amd": "^7.2.0", - "@babel/plugin-transform-modules-commonjs": "^7.4.4", - "@babel/plugin-transform-modules-systemjs": "^7.4.4", - "@babel/plugin-transform-modules-umd": "^7.2.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.5", - "@babel/plugin-transform-new-target": "^7.4.4", - "@babel/plugin-transform-object-super": "^7.2.0", - "@babel/plugin-transform-parameters": "^7.4.4", - "@babel/plugin-transform-property-literals": "^7.2.0", - "@babel/plugin-transform-regenerator": "^7.4.5", - "@babel/plugin-transform-reserved-words": "^7.2.0", - "@babel/plugin-transform-shorthand-properties": "^7.2.0", - "@babel/plugin-transform-spread": "^7.2.0", - "@babel/plugin-transform-sticky-regex": "^7.2.0", - "@babel/plugin-transform-template-literals": "^7.4.4", - "@babel/plugin-transform-typeof-symbol": "^7.2.0", - "@babel/plugin-transform-unicode-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "browserslist": "^4.6.0", - "core-js-compat": "^3.1.1", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.5.0" - }, - "dependencies": { - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" - } - } + "fill-range": "^7.0.1" } }, - "@babel/runtime": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.1.tgz", - "integrity": "sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==", + "browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", "dev": true, "requires": { - "regenerator-runtime": "^0.12.0" + "resolve": "^1.17.0" + } + }, + "buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" } }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "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.1" + "ms": "2.1.2" + } + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" } }, "fs-extra": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", - "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", - "universalify": "^1.0.0" + "universalify": "^2.0.0" } }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "regenerator-runtime": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", - "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", + "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 + }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "requires": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "stream-http": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", + "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "util": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", + "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, + "watchify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/watchify/-/watchify-4.0.0.tgz", + "integrity": "sha512-2Z04dxwoOeNxa11qzWumBTgSAohTC0+ScuY7XMenPnH+W2lhTcpEOJP4g2EIG/SWeLadPk47x++Yh+8BqPM/lA==", + "dev": true, + "requires": { + "anymatch": "^3.1.0", + "browserify": "^17.0.0", + "chokidar": "^3.4.0", + "defined": "^1.0.0", + "outpipe": "^1.1.0", + "through2": "^4.0.2", + "xtend": "^4.0.2" + }, + "dependencies": { + "browserify": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz", + "integrity": "sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w==", + "dev": true, + "requires": { + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^2.0.0", + "browserify-zlib": "~0.2.0", + "buffer": "~5.2.1", + "cached-path-relative": "^1.0.0", + "concat-stream": "^1.6.0", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.1", + "domain-browser": "^1.2.0", + "duplexer2": "~0.1.2", + "events": "^3.0.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.2.1", + "JSONStream": "^1.0.3", + "labeled-stream-splicer": "^2.0.0", + "mkdirp-classic": "^0.5.2", + "module-deps": "^6.2.3", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "^1.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum-object": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^3.0.0", + "stream-http": "^3.0.0", + "string_decoder": "^1.1.1", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "0.0.1", + "url": "~0.11.0", + "util": "~0.12.0", + "vm-browserify": "^1.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "requires": { + "readable-stream": "3" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + } + } } } }, "@cypress/code-coverage": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/@cypress/code-coverage/-/code-coverage-3.9.10.tgz", - "integrity": "sha512-aJokd9B1/cI8uQAH4tPw9yuZg7a/bdl1xO4xSeO4ly5Tlj8L3/eJ2vvJf5RcfHAZQE1OMOYY7ZtPuBBE8eItYw==", + "version": "3.9.12", + "resolved": "https://registry.npmjs.org/@cypress/code-coverage/-/code-coverage-3.9.12.tgz", + "integrity": "sha512-2QuDSQ2ovz2ZsbQImM917q+9JmEq4afC4kpgHe2o3rTQxUrs7CdHM84rT8XKl0gJIXmbMcNq2rZqe40/eFmCFw==", "dev": true, "requires": { - "@cypress/browserify-preprocessor": "3.0.1", + "@cypress/browserify-preprocessor": "3.0.2", "chalk": "4.1.2", - "dayjs": "1.10.6", - "debug": "4.3.2", + "dayjs": "1.10.7", + "debug": "4.3.3", "execa": "4.1.0", "globby": "11.0.4", "istanbul-lib-coverage": "3.0.0", @@ -23650,9 +24871,9 @@ "dev": true }, "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" @@ -23692,13 +24913,13 @@ } }, "@cypress/fiddle": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@cypress/fiddle/-/fiddle-1.19.2.tgz", - "integrity": "sha512-Ovl6kk/F/73ZrSjGx95FiuO/eIvfsVMzMsMtc1YOYD7ctiBqGCU6ucy65jNzj+VQRn59FStPyfEHt1udLxfTqQ==", + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/@cypress/fiddle/-/fiddle-1.19.3.tgz", + "integrity": "sha512-g8YMD6vRQk2LWil8BWo9hs4unHD2wvxkDm5uzeeYHjgy4eWIhFizSov7TNjUU1keX5svA8aXsh3x+yz8Q6dgzw==", "dev": true, "requires": { - "@cypress/browserify-preprocessor": "2.2.4", - "@textlint/markdown-to-ast": "6.2.6", + "@cypress/browserify-preprocessor": "3.0.1", + "@textlint/markdown-to-ast": "12.0.0", "arg": "4.1.3", "common-tags": "1.8.0", "debug": "4.2.0", @@ -23748,6 +24969,18 @@ "@babel/plugin-syntax-object-rest-spread": "^7.2.0" } }, + "@babel/plugin-transform-runtime": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz", + "integrity": "sha512-jIgkljDdq4RYDnJyQsiWbdvGeei/0MOTtSHKO/rfbd/mXBxNpdlulMx49L0HQ4pug1fXannxoqCI+fYSle9eSw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "resolve": "^1.8.1", + "semver": "^5.5.1" + } + }, "@babel/preset-env": { "version": "7.4.5", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.5.tgz", @@ -23805,18 +25038,33 @@ }, "dependencies": { "@babel/plugin-proposal-object-rest-spread": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.0.tgz", - "integrity": "sha512-B4qphdSTp0nLsWcuei07JPKeZej4+Hd22MdnulJXQa1nCcGSBlk8FiqenGERaPZ+PuYhz4Li2Wjc8yfJvHgUMw==", + "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==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.13.0" + "@babel/compat-data": "^7.16.0", + "@babel/helper-compilation-targets": "^7.16.0", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.16.0" } } } }, + "@babel/preset-react": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", + "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0" + } + }, "@babel/runtime": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.1.tgz", @@ -23827,9 +25075,9 @@ } }, "@cypress/browserify-preprocessor": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@cypress/browserify-preprocessor/-/browserify-preprocessor-2.2.4.tgz", - "integrity": "sha512-kMjkIFe6qka8Tkm9N3BrMB+Nn7WEAHIzEd3gfVoDL17Tr40xyOnKGuMhEkff1scd3RV3bjQxwQ9BQ6kI2nToAQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cypress/browserify-preprocessor/-/browserify-preprocessor-3.0.1.tgz", + "integrity": "sha512-sErmFSEr5287bLMRl0POGnyFtJCs/lSk5yxrUIJUIHZ8eDvtTEr0V93xRgLjJVG54gJU4MbpHy1mRPA9VZbtQA==", "dev": true, "requires": { "@babel/core": "7.4.5", @@ -23846,7 +25094,7 @@ "coffeeify": "3.0.1", "coffeescript": "1.12.7", "debug": "4.1.1", - "fs-extra": "7.0.1", + "fs-extra": "9.0.0", "lodash.clonedeep": "4.5.0", "through2": "^2.0.0", "watchify": "3.11.1" @@ -23872,6 +25120,18 @@ "ms": "2.1.2" } }, + "fs-extra": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", + "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -23883,13 +25143,19 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", "dev": true + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true } } }, "@cypress/request": { - "version": "2.88.6", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.6.tgz", - "integrity": "sha512-z0UxBE/+qaESAHY9p9sM2h8Y4XqtsbDCt0/DPOrqA/RZgKi4PkxdpXyK4wCCnSk1xHqWHZZAE+gV6aDAR6+caQ==", + "version": "2.88.10", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", + "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==", "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -23899,8 +25165,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", + "http-signature": "~1.3.6", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", @@ -23913,6 +25178,35 @@ "uuid": "^8.3.2" }, "dependencies": { + "http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + } + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -23964,61 +25258,40 @@ } } }, - "@es-joy/jsdoccomment": { - "version": "0.10.8", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.10.8.tgz", - "integrity": "sha512-3P1JiGL4xaR9PoTKUHa2N/LKwa2/eUdRqGwijMWWgBqbFEqJUVpmaOi2TcjcemrsRMgFLBzQCK4ToPhrSVDiFQ==", - "dev": true, - "requires": { - "comment-parser": "1.2.4", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "1.1.1" - } - }, "@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": { @@ -24027,48 +25300,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", @@ -24084,40 +25323,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", @@ -24563,12 +25768,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", @@ -24709,9 +25908,9 @@ } }, "@rollup/plugin-commonjs": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-18.0.0.tgz", - "integrity": "sha512-fj92shhg8luw7XbA0HowAqz90oo7qtLGwqTKbyZ8pmOyH8ui5e+u0wPEgeHLH3djcVma6gUCUrjY6w5R2o1u6g==", + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-18.1.0.tgz", + "integrity": "sha512-h3e6T9rUxVMAQswpDIobfUHn/doMzM9sgkMrsMWCFLmB84PSoC8mV8tOloAJjSRwdqhXBqstlX2BwBpHJvbhxg==", "dev": true, "requires": { "@rollup/pluginutils": "^3.1.0", @@ -24732,17 +25931,27 @@ } }, "@rollup/plugin-dynamic-import-vars": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-dynamic-import-vars/-/plugin-dynamic-import-vars-1.4.0.tgz", - "integrity": "sha512-oDeBDYJkD+VleSqSmWZo4h7iMHFYgEx/XVnJJZhCGuqkrS9QwOubESyWMqujBuUMeIByv954RvBTFvkAKlLh4A==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-dynamic-import-vars/-/plugin-dynamic-import-vars-1.4.2.tgz", + "integrity": "sha512-SEaS9Pf0RyaZ/oJ1knLZT+Fu0X6DlyTfUcoE7XKkiKJjNaB+8SLoHmDVRhomo5RpWHPyd+B00G/bE5R5+Q+HEg==", "dev": true, "requires": { - "@rollup/pluginutils": "^3.1.0", + "@rollup/pluginutils": "^4.1.2", "estree-walker": "^2.0.1", - "globby": "^11.0.1", + "fast-glob": "^3.2.7", "magic-string": "^0.25.7" }, "dependencies": { + "@rollup/pluginutils": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.2.tgz", + "integrity": "sha512-ROn4qvkxP9SyPeHaf7uQC/GPFY6L/OWy9+bd9AwcjOAWQwxRscoEyAUD8qCY5o5iL4jqQwoLk2kaTKJPb/HwzQ==", + "dev": true, + "requires": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + } + }, "estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -24762,9 +25971,9 @@ } }, "@rollup/plugin-node-resolve": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.4.tgz", - "integrity": "sha512-eYq4TFy40O8hjeDs+sIxEH/jc9lyuI2k9DM557WN6rO5OpnC2qXMBNj4IKH1oHrnAazL49C5p0tgP0/VpqJ+/w==", + "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", @@ -24776,9 +25985,9 @@ } }, "@rollup/plugin-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-3.0.0.tgz", - "integrity": "sha512-3c7JCbMuYXM4PbPWT4+m/4Y6U60SgsnDT/cCyAyUKwFHg7pTSfsSQzIpETha3a3ig6OdOKzZz87D9ZXIK3qsDg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-3.0.1.tgz", + "integrity": "sha512-989J5oRzf3mm0pO/0djTijdfEh9U3n63BIXN5X7T4U9BP+fN4oxQ6DvDuBvFaHA6scaHQRclqmKQEkBhB7k7Hg==", "dev": true, "requires": { "@rollup/pluginutils": "^3.1.0", @@ -24845,30 +26054,31 @@ "dev": true }, "@textlint/ast-node-types": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-4.4.1.tgz", - "integrity": "sha512-2QBwlqi2SU83vTHibfdTxGiLdIqR0btNyMGfVl0bwA6FI85HnSYoGFLrdCnq2V0nxpbhuvwzcm2Ja81w0VkMGA==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-12.1.0.tgz", + "integrity": "sha512-UlxqemrV/EnGTCl26OU7JhtFJpH7NZdgXvnsuII604orcIkvywUA1GGlg51grfbfqi+ar4zRsOb6fVbcbMZnKA==", "dev": true }, "@textlint/markdown-to-ast": { - "version": "6.2.6", - "resolved": "https://registry.npmjs.org/@textlint/markdown-to-ast/-/markdown-to-ast-6.2.6.tgz", - "integrity": "sha512-TjZTMGYla9Nznegy0r23EEzNMfWva0oksj+48aqMlbQ+UvBA5vdEC0VzCO3l0Z137RgEJ+glInbvEilo2zcjZg==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@textlint/markdown-to-ast/-/markdown-to-ast-12.0.0.tgz", + "integrity": "sha512-XaiuePJVDGVIwdjIiITdbdRXZDFnAFY/so3Rb8qAId/Qq9fKPUvgefMkdIG73wUC7LzhrAzH6/CuEO+f77HR5g==", "dev": true, "requires": { - "@textlint/ast-node-types": "^4.3.5", + "@textlint/ast-node-types": "^12.0.0", "debug": "^4.3.1", - "remark-frontmatter": "^1.3.3", - "remark-parse": "^5.0.0", - "structured-source": "^3.0.2", + "remark-footnotes": "^3.0.0", + "remark-frontmatter": "^3.0.0", + "remark-gfm": "^1.0.0", + "remark-parse": "^9.0.0", "traverse": "^0.6.6", - "unified": "^6.2.0" + "unified": "^9.2.1" }, "dependencies": { "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" @@ -24904,9 +26114,9 @@ } }, "@types/body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", "dev": true, "requires": { "@types/connect": "*", @@ -24988,9 +26198,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz", - "integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==", + "version": "4.17.26", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz", + "integrity": "sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==", "dev": true, "requires": { "@types/node": "*", @@ -25018,9 +26228,9 @@ } }, "@types/http-assert": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.2.tgz", - "integrity": "sha512-Ddzuzv/bB2prZnJKlS1sEYhaeT50wfJjhcTTTQLjEsEZJlk3XB4Xohieyq+P4VXIzg7lrQ1Spd/PfRnBpQsdqA==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.3.tgz", + "integrity": "sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==", "dev": true }, "@types/http-errors": { @@ -25130,9 +26340,9 @@ "dev": true }, "@types/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-ARATsLdrGPUnaBvxLhUlnltcMgn7pQG312S8ccdYlnyijabrX9RN/KN/iGj9Am96CoW8e/K9628BA7Bv4XHdrA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", + "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==", "dev": true }, "@types/qs": { @@ -25254,42 +26464,27 @@ } }, "@web/dev-server": { - "version": "0.1.22", - "resolved": "https://registry.npmjs.org/@web/dev-server/-/dev-server-0.1.22.tgz", - "integrity": "sha512-8PZxz2PGK9Ndr0C2LtWHrTzPKkDYTP/IvEMs9nrIebQWxvVjxI/HpvNfli3ivvCtvvcJFI26FvfWaAWDq14GgQ==", + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/@web/dev-server/-/dev-server-0.1.29.tgz", + "integrity": "sha512-oDz6vC9JEDZd4ZTno+SV57zCpsQl9v5LOkGuWGyei5gx5xu8NVDvh2IgTugz6DhZnffsSE6Zi0ubs+AhonLnGA==", "dev": true, "requires": { "@babel/code-frame": "^7.12.11", - "@rollup/plugin-node-resolve": "^11.0.1", "@types/command-line-args": "^5.0.0", "@web/config-loader": "^0.1.3", - "@web/dev-server-core": "^0.3.14", - "@web/dev-server-rollup": "^0.3.9", + "@web/dev-server-core": "^0.3.17", + "@web/dev-server-rollup": "^0.3.13", "camelcase": "^6.2.0", - "chalk": "^4.1.0", "command-line-args": "^5.1.1", "command-line-usage": "^6.1.1", "debounce": "^1.2.0", "deepmerge": "^4.2.2", "ip": "^1.1.5", + "nanocolors": "^0.2.1", "open": "^8.0.2", "portfinder": "^1.0.28" }, "dependencies": { - "@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - } - }, "array-back": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", @@ -25302,51 +26497,6 @@ "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "dev": true }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "command-line-usage": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", @@ -25372,12 +26522,6 @@ } } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "typical": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", @@ -25387,9 +26531,9 @@ } }, "@web/dev-server-core": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@web/dev-server-core/-/dev-server-core-0.3.14.tgz", - "integrity": "sha512-QHWGbkLI7qZVkELd6a7R4llRF9zydwbZagAeiJRvOIIiDhG5Uu9DfAWAQL+RSCb2hqBlEnaVAK4keNffKol4rQ==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@web/dev-server-core/-/dev-server-core-0.3.17.tgz", + "integrity": "sha512-vN1dwQ8yDHGiAvCeUo9xFfjo+pFl8TW+pON7k9kfhbegrrB8CKhJDUxmHbZsyQUmjf/iX57/LhuWj1xGhRL8AA==", "dev": true, "requires": { "@types/koa": "^2.11.6", @@ -25397,7 +26541,7 @@ "@web/parse5-utils": "^1.2.0", "chokidar": "^3.4.3", "clone": "^2.1.2", - "es-module-lexer": "^0.7.1", + "es-module-lexer": "^0.9.0", "get-stream": "^6.0.0", "is-stream": "^2.0.0", "isbinaryfile": "^4.0.6", @@ -25526,81 +26670,68 @@ } }, "@web/dev-server-rollup": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@web/dev-server-rollup/-/dev-server-rollup-0.3.9.tgz", - "integrity": "sha512-8NOV8GxcDXk9u+hsVYllGiMhcORYMFK+LtLT4HIg3+emW64j0MynttowBoOFpgwv7YOuVQ6lWe1kmJxiI+TRdg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@web/dev-server-rollup/-/dev-server-rollup-0.3.13.tgz", + "integrity": "sha512-QaxEtsdL6+fktIa1ZL8VEtq4U7WB7ikKEnxkbhUpFknB+WSvwx6DUrvyBDuPckunpczCnljXBFPugu+2W6N8Fg==", "dev": true, "requires": { - "@web/dev-server-core": "^0.3.3", - "chalk": "^4.1.0", + "@rollup/plugin-node-resolve": "^11.0.1", + "@web/dev-server-core": "^0.3.16", + "nanocolors": "^0.2.1", "parse5": "^6.0.1", - "rollup": "^2.56.2", - "whatwg-url": "^9.0.0" + "rollup": "^2.58.0", + "whatwg-url": "^11.0.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "parse5": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "punycode": "^2.1.1" } }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true + }, "whatwg-url": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-9.1.0.tgz", - "integrity": "sha512-CQ0UcrPHyomtlOCot1TL77WyMIm/bCwrJ2D6AOKGwEczU9EpyoqAokfqrf/MioU9kHcMsmJZcg1egXix2KYEsA==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dev": true, "requires": { - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" } } } @@ -25662,9 +26793,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": {} }, @@ -25840,9 +26971,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": { @@ -25860,12 +26991,6 @@ "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==", "dev": true }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", - "dev": true - }, "anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", @@ -25964,16 +27089,16 @@ "dev": true }, "array-includes": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", - "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", + "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", - "is-string": "^1.0.5" + "is-string": "^1.0.7" } }, "array-union": { @@ -25989,14 +27114,25 @@ "dev": true }, "array.prototype.flat": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", + "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "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.18.0-next.1" + "es-abstract": "^1.19.0" } }, "arraybuffer.slice": { @@ -26079,15 +27215,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", @@ -26132,6 +27259,12 @@ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -26144,12 +27277,6 @@ "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==", "dev": true }, - "axe-core": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.3.tgz", - "integrity": "sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA==", - "dev": true - }, "axios": { "version": "0.21.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", @@ -26178,13 +27305,13 @@ } }, "babel-plugin-polyfill-corejs2": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", - "integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.0.tgz", + "integrity": "sha512-wMDoBJ6uG4u4PNFh72Ty6t3EgfA91puCuAwKIazbQlci+ENb/UU9A3xG5lutjUIiXCIn1CY5L15r9LimiJyrSA==", "dev": true, "requires": { "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.2.2", + "@babel/helper-define-polyfill-provider": "^0.3.0", "semver": "^6.1.1" }, "dependencies": { @@ -26197,22 +27324,22 @@ } }, "babel-plugin-polyfill-corejs3": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.3.tgz", - "integrity": "sha512-rCOFzEIJpJEAU14XCcV/erIf/wZQMmMT5l5vXOpL5uoznyOGfDIjPj6FVytMvtzaKSTSVKouOCTPJ5OMUZH30g==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz", + "integrity": "sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.2", - "core-js-compat": "^3.14.0" + "@babel/helper-define-polyfill-provider": "^0.3.0", + "core-js-compat": "^3.18.0" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz", - "integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.0.tgz", + "integrity": "sha512-dhAPTDLGoMW5/84wkgwiLRwMnio2i1fUe53EuvtKMv0pn2p3S8OCoV1xAzfJPl0KOX7IB89s2ib85vbYiea3jg==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.2" + "@babel/helper-define-polyfill-provider": "^0.3.0" } }, "babel-plugin-syntax-object-rest-spread": { @@ -26277,35 +27404,6 @@ "requires": { "is-descriptor": "^1.0.0" } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } } } }, @@ -26390,12 +27488,6 @@ "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", "dev": true }, - "boundary": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/boundary/-/boundary-1.0.1.tgz", - "integrity": "sha1-TWfcJgLAzBbdm85+v4fpSCkPWBI=", - "dev": true - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -26422,17 +27514,6 @@ "snapdragon-node": "^2.0.1", "split-string": "^3.0.2", "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } } }, "brorand": { @@ -26451,9 +27532,9 @@ } }, "browser-fs-access": { - "version": "0.20.4", - "resolved": "https://registry.npmjs.org/browser-fs-access/-/browser-fs-access-0.20.4.tgz", - "integrity": "sha512-rSbY1AIoDe+fvYZ1LiRDdKBnytfsd1nN/GKS/DRZAhaJkz3cfbp14IHw5lk4FFWBelD6Sw6EtdnAI990ZuBZjg==" + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/browser-fs-access/-/browser-fs-access-0.23.0.tgz", + "integrity": "sha512-MMkxI9sHD5c//9qVFW8qM6qY9n/3PhLR6LhqMalJZK83O0/wrmzrzafy0JCGkaXvXcW5PC+Mq+A31DGoDkdQ9Q==" }, "browser-pack": { "version": "6.1.0", @@ -26648,16 +27729,16 @@ } }, "browserslist": { - "version": "4.16.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.8.tgz", - "integrity": "sha512-sc2m9ohR/49sWEbPj14ZSSZqp+kbi16aLao42Hmn3Z8FpjuMaq2xCA2l4zl9ITfyzvnvyE0hcg62YkIGKxgaNQ==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.18.1.tgz", + "integrity": "sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001251", - "colorette": "^1.3.0", - "electron-to-chromium": "^1.3.811", + "caniuse-lite": "^1.0.30001280", + "electron-to-chromium": "^1.3.896", "escalade": "^3.1.1", - "node-releases": "^1.1.75" + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" } }, "btoa": { @@ -26843,6 +27924,16 @@ "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", "dev": true }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -26876,22 +27967,24 @@ } }, "caniuse-lite": { - "version": "1.0.30001251", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz", - "integrity": "sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A==", + "version": "1.0.30001284", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001284.tgz", + "integrity": "sha512-t28SKa7g6kiIQi6NHeOcKrOrGMzCRrXvlasPwWC26TH2QNdglgzQIRUuJ0cR3NeQPH+5jpuveeeSFDLm2zbkEw==", "dev": true }, "canvg": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.7.tgz", - "integrity": "sha512-4sq6iL5Q4VOXS3PL1BapiXIZItpxYyANVzsAKpTPS5oq4u3SKbGfUcbZh2gdLCQ3jWpG/y5wRkMlBBAJhXeiZA==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.9.tgz", + "integrity": "sha512-rDXcnRPuz4QHoCilMeoTxql+fvGqNAxp+qV/KHD8rOiJSAfVjFclbdUNHD2Uqfthr+VMg17bD2bVuk6F07oLGw==", "requires": { - "@babel/runtime-corejs3": "^7.9.6", + "@babel/runtime": "^7.12.5", "@types/raf": "^3.4.0", + "core-js": "^3.8.3", "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", "rgbcolor": "^1.0.1", "stackblur-canvas": "^2.0.0", - "svg-pathdata": "^5.0.5" + "svg-pathdata": "^6.0.3" } }, "caseless": { @@ -26909,6 +28002,12 @@ "lodash": "^4.17.15" } }, + "ccount": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", + "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==", + "dev": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -27000,6 +28099,80 @@ "requires": { "is-descriptor": "^0.1.0" } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true } } }, @@ -27090,12 +28263,6 @@ "integrity": "sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA==", "dev": true }, - "collapse-white-space": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", - "dev": true - }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -27180,12 +28347,6 @@ "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "dev": true }, - "comment-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.2.4.tgz", - "integrity": "sha512-pm0b+qv+CkWNriSTMsfnjChF9kH0kxz55y44Wo5le9qLxMj5xDQAaEd9ZN1ovSuk9CsrncWaFwgpOMg7ClJwkw==", - "dev": true - }, "common-tags": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", @@ -27403,23 +28564,23 @@ } }, "core-js": { - "version": "3.16.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.3.tgz", - "integrity": "sha512-lM3GftxzHNtPNUJg0v4pC2RC6puwMd6VZA7vXUczi+SKmCWSf4JwO89VJGMqbzmB7jlK7B5hr3S64PqwFL49cA==" + "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.16.3", - "resolved": "https://registry.npmjs.org/core-js-bundle/-/core-js-bundle-3.16.3.tgz", - "integrity": "sha512-h2AiKHbsoj0RwI4mQqteOhdYxeKClV8QK0LoB92QDaggKgkQ+PSQyLGu0uV8bhXdyuPKB9VvdcCJa6k7OSlo5w==", + "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": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.16.0.tgz", - "integrity": "sha512-5D9sPHCdewoUK7pSUPfTF7ZhLh8k9/CoJXWUEo+F1dZT5Z1DVgcuRqUKhjeKW+YLb8f21rTFgWwQJiNw1hoZ5Q==", + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.19.2.tgz", + "integrity": "sha512-ObBY1W5vx/LFFMaL1P5Udo4Npib6fu+cMokeziWkA8Tns4FcDemKF5j9JvaI5JhdkW8EQJQGJN1EcrzmEwuAqQ==", "dev": true, "requires": { - "browserslist": "^4.16.6", + "browserslist": "^4.18.1", "semver": "7.0.0" }, "dependencies": { @@ -27432,9 +28593,10 @@ } }, "core-js-pure": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.16.0.tgz", - "integrity": "sha512-wzlhZNepF/QA9yvx3ePDgNGudU5KDB8lu/TRPKelYA/QtSnkS/cLl2W+TIdEX1FAFcBr0YpY7tPDlcmXJ7AyiQ==" + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.2.tgz", + "integrity": "sha512-5LkcgQEy8pFeVnd/zomkUBSwnmIxuF1C8E9KrMAbOc8f34IBT9RGvTYeNDdp1PnvMJrrVhvk1hg/yVV5h/znlg==", + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -27729,19 +28891,19 @@ } }, "cypress": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-8.3.1.tgz", - "integrity": "sha512-1v6pfx+/5cXhaT5T6QKOvnkawmEHWHLiVzm3MYMoQN1fkX2Ma1C32STd3jBStE9qT5qPSTILjGzypVRxCBi40g==", + "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.6", + "@cypress/request": "^2.88.10", "@cypress/xvfb": "^1.2.4", "@types/node": "^14.14.31", "@types/sinonjs__fake-timers": "^6.0.2", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", "blob-util": "^2.0.2", - "bluebird": "^3.7.2", + "bluebird": "3.7.2", "cachedir": "^2.3.0", "chalk": "^4.1.0", "check-more-types": "^2.24.0", @@ -27768,7 +28930,7 @@ "minimist": "^1.2.5", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", - "ramda": "~0.27.1", + "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", "supports-color": "^8.1.1", "tmp": "~0.2.1", @@ -27926,22 +29088,9 @@ "requires": { "has-flag": "^4.0.0" } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true } } }, - "cypress-axe": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/cypress-axe/-/cypress-axe-0.13.0.tgz", - "integrity": "sha512-fCIy7RiDCm7t30U3C99gGwQrUO307EYE1QqXNaf9ToK4DVqW8y5on+0a/kUHMrHdlls2rENF6TN9ZPpPpwLrnw==", - "dev": true, - "requires": {} - }, "cypress-multi-reporters": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/cypress-multi-reporters/-/cypress-multi-reporters-1.5.0.tgz", @@ -28030,9 +29179,9 @@ } }, "dayjs": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.6.tgz", - "integrity": "sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", + "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==", "dev": true }, "debounce": { @@ -28142,37 +29291,6 @@ "requires": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } } }, "defined": { @@ -28349,27 +29467,11 @@ } } }, - "domhandler": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", - "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", - "dev": true, - "requires": { - "domelementtype": "^2.1.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", - "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==", - "dev": true - } - } - }, "dompurify": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.2.6.tgz", - "integrity": "sha512-7b7ZArhhH0SP6W2R9cqK6RjaU82FZ2UPM7RO8qN1b1wyvC/NY1FNWcX1Pu00fFOAnzEORtwXe4bPaClg6pUybQ==" + "integrity": "sha512-7b7ZArhhH0SP6W2R9cqK6RjaU82FZ2UPM7RO8qN1b1wyvC/NY1FNWcX1Pu00fFOAnzEORtwXe4bPaClg6pUybQ==", + "devOptional": true }, "duplexer": { "version": "0.1.1", @@ -28403,15 +29505,15 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.822", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.822.tgz", - "integrity": "sha512-k7jG5oYYHxF4jx6PcqwHX3JVME/OjzolqOZiIogi9xtsfsmTjTdie4x88OakYFPEa8euciTgCCzvVNwvmjHb1Q==", + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.11.tgz", + "integrity": "sha512-2OhsaYgsWGhWjx2et8kaUcdktPbBGjKM2X0BReUCKcSCPttEY+hz2zie820JLbttU8jwL92+JJysWwkut3wZgA==", "dev": true }, "elix": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/elix/-/elix-15.0.0.tgz", - "integrity": "sha512-Va7hBkoR/tEdn8v8JD6gdgxm4fd5JRLlLCpxMLd9OyLUps+vEesa19YuziPstWy3bexu7+Z3dxhWOeKX11zkHg==" + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/elix/-/elix-15.0.1.tgz", + "integrity": "sha512-hgL6EDdMO/JBJLmDfaM8AL0f3zQXDIwkjQEhaLi9OTLV+3q445ErkBZuHGK9UzAoIq3I062ldDXRX48l1vfqCg==" }, "elliptic": { "version": "6.5.3", @@ -28613,22 +29715,25 @@ } }, "es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-symbols": "^1.0.2", "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", + "is-callable": "^1.2.4", "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", "object-inspect": "^1.11.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", @@ -28638,9 +29743,9 @@ } }, "es-module-lexer": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.7.1.tgz", - "integrity": "sha512-MgtWFl5No+4S3TmhDmCz2ObFGm6lEpTnzbQi+Dd+pw4mlTIZTmM2iAs5gRlmx5zS9luzobCSBSI90JM/1/JgOw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, "es-to-primitive": { @@ -28701,32 +29806,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", @@ -28734,7 +29836,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", @@ -28743,20 +29845,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", @@ -28792,89 +29885,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", @@ -28885,12 +29909,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": { @@ -28905,16 +29929,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", @@ -28951,18 +29965,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", @@ -28972,12 +29974,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", @@ -28995,12 +29991,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 } } }, @@ -29011,6 +30001,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", @@ -29039,12 +30036,13 @@ } }, "eslint-module-utils": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz", - "integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", + "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", "dev": true, "requires": { "debug": "^3.2.7", + "find-up": "^2.1.0", "pkg-dir": "^2.0.0" }, "dependencies": { @@ -29117,154 +30115,24 @@ } } }, - "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": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-chai-expect/-/eslint-plugin-chai-expect-2.2.0.tgz", - "integrity": "sha512-ExTJKhgeYMfY8wDj3UiZmgpMKJOUHGNHmWMlxT49JUDB1vTnw0sSNfXJSxnX+LcebyBD/gudXzjzD136WqPJrQ==", - "dev": true - }, - "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": "3.13.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-3.13.0.tgz", - "integrity": "sha512-cv8IYMuTXm7PIjMVDN2y4k/KVnKZmoNGHNq27/9dLstOLydKblieIv+oe2BN2WthuXnFNhaNvv3N1Bvl4dbIGA==", - "dev": true, - "requires": { - "@mdn/browser-compat-data": "^3.3.14", - "ast-metadata-inferer": "^0.7.0", - "browserslist": "^4.16.8", - "caniuse-lite": "^1.0.30001251", - "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.11.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.11.3.tgz", - "integrity": "sha512-hOoAid+XNFtpvOzZSNWP5LDrQBEJwbZwjib4XJ1KcRYKjeVj0mAmPmucG4Egli4j/aruv+Ow/acacoloWWCl9Q==", - "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.1.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-6.1.2.tgz", - "integrity": "sha512-bhBIRyZFqI4EoF12lGDHAmgfff8eLXx6R52/K3ESQhsxzCzIE6hdebS7Py651f7U3RBotqroUnC3L29bR7qJWQ==", - "dev": true, - "requires": { - "htmlparser2": "^6.0.1" - } - }, "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==", + "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.3", - "array.prototype.flat": "^1.2.4", + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", "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", + "eslint-module-utils": "^2.7.1", "has": "^1.0.3", - "is-core-module": "^2.6.0", + "is-core-module": "^2.8.0", + "is-glob": "^4.0.3", "minimatch": "^3.0.4", - "object.values": "^1.1.4", - "pkg-up": "^2.0.0", - "read-pkg-up": "^3.0.0", + "object.values": "^1.1.5", "resolve": "^1.20.0", "tsconfig-paths": "^3.11.0" }, @@ -29274,126 +30142,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" } - }, - "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 } } }, - "eslint-plugin-jsdoc": { - "version": "36.0.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-36.0.8.tgz", - "integrity": "sha512-brNjHvRuBy5CaV01mSp6WljrO/T8fHNj0DXG38odOGDnhI7HdcbLKX7DpSvg2Rfcifwh8GlnNFzx13sI05t3bg==", - "dev": true, - "requires": { - "@es-joy/jsdoccomment": "0.10.8", - "comment-parser": "1.2.4", - "debug": "^4.3.2", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "^1.1.1", - "lodash": "^4.17.21", - "regextras": "^0.8.0", - "semver": "^7.3.5", - "spdx-expression-parse": "^3.0.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==", - "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 - }, - "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.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-2.2.0.tgz", - "integrity": "sha512-Ctuc7aP1tU92qnFwVO1wDLEzf1jqMxwRkcSTw7gjbvnEqfh5CKUcTXM0sxg8CB2KDXrqpTuMZPgJ1XE9Olr7KA==", - "dev": true, - "requires": { - "mdast-util-from-markdown": "^0.8.5" - } - }, - "eslint-plugin-no-unsanitized": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-3.1.5.tgz", - "integrity": "sha512-s/6w++p1590h/H/dE2Wo660bOkaM/3OEK14Y7xm1UT0bafxkKw1Cq0ksjxkxLdH/WWd014DlsLKuD6CyNrR2Dw==", - "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", @@ -29418,21 +30173,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", @@ -29442,17 +30182,78 @@ } }, "eslint-plugin-promise": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.0.tgz", - "integrity": "sha512-NGmI6BH5L12pl7ScQHbg7tvtk4wPxxj8yPHH47NvSmMtFneC077PSeY3huFj06ZWZvtbfxSPt3RuOQD5XcR4ng==", + "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", @@ -29460,6 +30261,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", @@ -29483,6 +30295,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", @@ -29607,14 +30436,62 @@ "is-descriptor": "^0.1.0" } }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true } } }, @@ -29625,24 +30502,12 @@ "dev": true }, "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "is-extendable": "^0.1.0" } }, "extglob": { @@ -29669,44 +30534,6 @@ "requires": { "is-descriptor": "^1.0.0" } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } } } }, @@ -29752,17 +30579,16 @@ "dev": true }, "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" }, "dependencies": { "braces": { @@ -29784,9 +30610,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -29799,13 +30625,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "to-regex-range": { @@ -29921,17 +30747,6 @@ "is-number": "^3.0.0", "repeat-string": "^1.6.1", "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } } }, "find-cache-dir": { @@ -30003,6 +30818,12 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, "foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -30217,12 +31038,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", @@ -30238,6 +31053,16 @@ "pump": "^3.0.0" } }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -30546,8 +31371,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "peer": true + "dev": true }, "hmac-drbg": { "version": "1.0.1", @@ -30599,10 +31423,33 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dev": true, + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + } + } + }, "html2canvas": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.3.2.tgz", - "integrity": "sha512-4+zqv87/a1LsaCrINV69wVLGG8GBZcYBboz1JPWEgiXcWoD9kroLzccsBRU/L9UlfV2MAZ+3J92U9IQPVMDeSQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.3.4.tgz", + "integrity": "sha512-81pWiqkzRVu5ap/IEd4g+YDAZu3ozTFvJxnlRfrRVQ4JK4A1optD6Qu4YhGF2HdPZXzt89KwUi1C9TmH1O8Etg==", "requires": { "css-line-break": "2.0.1", "text-segmentation": "^1.0.2" @@ -30614,77 +31461,14 @@ "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", "dev": true }, - "htmlparser2": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.0.1.tgz", - "integrity": "sha512-GDKPd+vk4jvSuvCbyuzx/unmXkk090Azec7LovXP8as1Hn8q9p3hbjmDGbUqqhknw0ajwit6LiiWqfiTUPMK7w==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.4.4", - "entities": "^2.0.0" - }, - "dependencies": { - "dom-serializer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", - "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", - "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==", - "dev": true - }, - "domutils": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.4.tgz", - "integrity": "sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==", - "dev": true, - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0" - } - } - } - }, "http-assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.4.1.tgz", - "integrity": "sha512-rdw7q6GTlibqVVbXr0CKelfV5iY8G2HqEUkhSk297BMbSpSL8crXC+9rjKoMcZZEsksX30le6f/4ul4E28gegw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz", + "integrity": "sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==", "dev": true, "requires": { "deep-equal": "~1.0.1", - "http-errors": "~1.7.2" - }, - "dependencies": { - "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "dev": true - } + "http-errors": "~1.8.0" } }, "http-cache-semantics": { @@ -30694,16 +31478,16 @@ "dev": true }, "http-errors": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.0.tgz", - "integrity": "sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dev": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" } }, "http-proxy-agent": { @@ -30794,9 +31578,9 @@ } }, "i18next": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-20.4.0.tgz", - "integrity": "sha512-89iWWJudmaHJwzIdJ/1eu98GtsJnwBhOUWwlAre70itPMuTE/NTPtgVeaS1CGaB8Q3XrYBGpEqlq4jsScDx9kg==", + "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" } @@ -30837,6 +31621,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", @@ -30978,23 +31780,12 @@ "dev": true }, "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "kind-of": "^6.0.0" } }, "is-alphabetical": { @@ -31013,6 +31804,16 @@ "is-decimal": "^1.0.0" } }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -31050,38 +31851,27 @@ "dev": true }, "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true }, "is-core-module": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", - "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", "dev": true, "requires": { "has": "^1.0.3" } }, "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "kind-of": "^6.0.0" } }, "is-date-object": { @@ -31097,22 +31887,14 @@ "dev": true }, "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } }, "is-docker": { @@ -31160,20 +31942,10 @@ "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.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" @@ -31185,15 +31957,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", @@ -31238,16 +32001,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", @@ -31281,16 +32034,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", @@ -31310,6 +32053,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "dev": true + }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -31334,6 +32083,19 @@ "has-symbols": "^1.0.1" } }, + "is-typed-array": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", + "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.5", + "foreach": "^2.0.5", + "has-tostringtag": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -31346,11 +32108,14 @@ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, - "is-whitespace-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", - "dev": true + "is-weakref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", + "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0" + } }, "is-windows": { "version": "1.0.2", @@ -31358,12 +32123,6 @@ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, - "is-word-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", - "dev": true - }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -31642,12 +32401,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", @@ -31712,21 +32465,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": "1.1.1", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-1.1.1.tgz", - "integrity": "sha512-uelRmpghNwPBuZScwgBG/OzodaFk5RbO5xaivBdsAY70icWfShwZ7PCMO0x1zSkOa8T1FzHThmrdoyg/0AwV5g==", - "dev": true - }, "jsdom": { "version": "16.4.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", @@ -31829,14 +32570,6 @@ "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" - }, - "dependencies": { - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } } }, "jsonify": { @@ -31862,10 +32595,11 @@ } }, "jspdf": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.3.1.tgz", - "integrity": "sha512-1vp0USP1mQi1h7NKpwxjFgQkJ5ncZvtH858aLpycUc/M+r/RpWJT8PixAU7Cw/3fPd4fpC8eB/Bj42LnsR21YQ==", + "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", "btoa": "^1.2.1", "canvg": "^3.0.6", @@ -31887,6 +32621,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", @@ -31912,9 +32656,9 @@ } }, "koa": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.1.tgz", - "integrity": "sha512-Lb2Dloc72auj5vK4X4qqL7B5jyDPQaZucc9sR/71byg7ryoD1NCaCm63CShk9ID9quQvDEi1bGR/iGjCG7As3w==", + "version": "2.13.4", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.4.tgz", + "integrity": "sha512-43zkIKubNbnrULWlHdN5h1g3SEKXOEzoAlRsHOTFpnlDu8JlAOZSMJBLULusuXRequboiwJcj5vtYXKB3k7+2g==", "dev": true, "requires": { "accepts": "^1.3.5", @@ -31922,7 +32666,7 @@ "content-disposition": "~0.5.2", "content-type": "^1.0.4", "cookies": "~0.8.0", - "debug": "~3.1.0", + "debug": "^4.3.2", "delegates": "^1.0.0", "depd": "^2.0.0", "destroy": "^1.0.4", @@ -31933,7 +32677,7 @@ "http-errors": "^1.6.3", "is-generator-function": "^1.0.7", "koa-compose": "^4.1.0", - "koa-convert": "^1.2.0", + "koa-convert": "^2.0.0", "on-finished": "^2.3.0", "only": "~0.0.2", "parseurl": "^1.3.2", @@ -31943,12 +32687,12 @@ }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "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.0.0" + "ms": "2.1.2" } }, "depd": { @@ -31956,6 +32700,12 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "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 } } }, @@ -31966,24 +32716,13 @@ "dev": true }, "koa-convert": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-1.2.0.tgz", - "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-2.0.0.tgz", + "integrity": "sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==", "dev": true, "requires": { "co": "^4.6.0", - "koa-compose": "^3.0.0" - }, - "dependencies": { - "koa-compose": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", - "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", - "dev": true, - "requires": { - "any-promise": "^1.1.0" - } - } + "koa-compose": "^4.1.0" } }, "koa-etag": { @@ -32007,9 +32746,9 @@ }, "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" @@ -32278,12 +33017,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", @@ -32427,10 +33160,10 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", "dev": true }, "lru-cache": { @@ -32519,12 +33252,6 @@ "object-visit": "^1.0.0" } }, - "markdown-escapes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", - "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", - "dev": true - }, "markdown-it": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", @@ -32544,6 +33271,15 @@ "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", "dev": true }, + "markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "dev": true, + "requires": { + "repeat-string": "^1.0.0" + } + }, "marked": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.3.tgz", @@ -32561,6 +33297,69 @@ "safe-buffer": "^5.1.2" } }, + "mdast-util-find-and-replace": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-1.1.1.tgz", + "integrity": "sha512-9cKl33Y21lyckGzpSmEQnIDjEfeeWelN5s1kUW1LwdB0Fkuq2u+4GdqcGEygYxJE8GVqCl0741bYXHgamfWAZA==", + "dev": true, + "requires": { + "escape-string-regexp": "^4.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "dependencies": { + "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 + } + } + }, + "mdast-util-footnote": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/mdast-util-footnote/-/mdast-util-footnote-0.1.7.tgz", + "integrity": "sha512-QxNdO8qSxqbO2e3m09KwDKfWiLgqyCurdWTQ198NpbZ2hxntdc+VKS4fDJCmNWbAroUdYnSthu+XbZ8ovh8C3w==", + "dev": true, + "requires": { + "mdast-util-to-markdown": "^0.6.0", + "micromark": "~2.11.0" + }, + "dependencies": { + "longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true + }, + "mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + } + }, + "mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true + }, + "zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true + } + } + }, "mdast-util-from-markdown": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", @@ -32579,29 +33378,203 @@ "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", "dev": true + } + } + }, + "mdast-util-frontmatter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-0.2.0.tgz", + "integrity": "sha512-FHKL4w4S5fdt1KjJCwB0178WJ0evnyyQr5kXTM3wrOVpytD0hrkvd+AOOjU9Td8onOejCkmZ+HQRT3CZ3coHHQ==", + "dev": true, + "requires": { + "micromark-extension-frontmatter": "^0.2.0" + } + }, + "mdast-util-gfm": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-0.1.2.tgz", + "integrity": "sha512-NNkhDx/qYcuOWB7xHUGWZYVXvjPFFd6afg6/e2g+SV4r9q5XUcCbV4Wfa3DLYIiD+xAEZc6K4MGaE/m0KDcPwQ==", + "dev": true, + "requires": { + "mdast-util-gfm-autolink-literal": "^0.1.0", + "mdast-util-gfm-strikethrough": "^0.2.0", + "mdast-util-gfm-table": "^0.1.0", + "mdast-util-gfm-task-list-item": "^0.1.0", + "mdast-util-to-markdown": "^0.6.1" + }, + "dependencies": { + "longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true }, - "parse-entities": { + "mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + } + }, + "mdast-util-to-string": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true + }, + "zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true + } + } + }, + "mdast-util-gfm-autolink-literal": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-0.1.3.tgz", + "integrity": "sha512-GjmLjWrXg1wqMIO9+ZsRik/s7PLwTaeCHVB7vRxUwLntZc8mzmTsLVr6HW1yLokcnhfURsn5zmSVdi3/xWWu1A==", + "dev": true, + "requires": { + "ccount": "^1.0.0", + "mdast-util-find-and-replace": "^1.1.0", + "micromark": "^2.11.3" + } + }, + "mdast-util-gfm-strikethrough": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-0.2.3.tgz", + "integrity": "sha512-5OQLXpt6qdbttcDG/UxYY7Yjj3e8P7X16LzvpX8pIQPYJ/C2Z1qFGMmcw+1PZMUM3Z8wt8NRfYTvCni93mgsgA==", + "dev": true, + "requires": { + "mdast-util-to-markdown": "^0.6.0" + }, + "dependencies": { + "longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true + }, + "mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", "dev": true, "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" } }, - "unist-util-stringify-position": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true + }, + "zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true + } + } + }, + "mdast-util-gfm-table": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-0.1.6.tgz", + "integrity": "sha512-j4yDxQ66AJSBwGkbpFEp9uG/LS1tZV3P33fN1gkyRB2LoRL+RR3f76m0HPHaby6F4Z5xr9Fv1URmATlRRUIpRQ==", + "dev": true, + "requires": { + "markdown-table": "^2.0.0", + "mdast-util-to-markdown": "~0.6.0" + }, + "dependencies": { + "longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true + }, + "mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", "dev": true, "requires": { - "@types/unist": "^2.0.2" + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" } + }, + "mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true + }, + "zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true + } + } + }, + "mdast-util-gfm-task-list-item": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-0.1.6.tgz", + "integrity": "sha512-/d51FFIfPsSmCIRNp7E6pozM9z1GYPIkSy1urQ8s/o4TC22BZ7DqfHFWiqBD23bc7J3vV1Fc9O4QIHBlfuit8A==", + "dev": true, + "requires": { + "mdast-util-to-markdown": "~0.6.0" + }, + "dependencies": { + "longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true + }, + "mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + } + }, + "mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true + }, + "zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true } } }, @@ -32906,20 +33879,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true - }, - "parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "dev": true, - "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - } } } }, @@ -33008,6 +33967,80 @@ } } }, + "micromark-extension-footnote": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/micromark-extension-footnote/-/micromark-extension-footnote-0.3.2.tgz", + "integrity": "sha512-gr/BeIxbIWQoUm02cIfK7mdMZ/fbroRpLsck4kvFtjbzP4yi+OPVbnukTc/zy0i7spC2xYE/dbX1Sur8BEDJsQ==", + "dev": true, + "requires": { + "micromark": "~2.11.0" + } + }, + "micromark-extension-frontmatter": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-0.2.2.tgz", + "integrity": "sha512-q6nPLFCMTLtfsctAuS0Xh4vaolxSFUWUWR6PZSrXXiRy+SANGllpcqdXFv2z07l0Xz/6Hl40hK0ffNCJPH2n1A==", + "dev": true, + "requires": { + "fault": "^1.0.0" + } + }, + "micromark-extension-gfm": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-0.3.3.tgz", + "integrity": "sha512-oVN4zv5/tAIA+l3GbMi7lWeYpJ14oQyJ3uEim20ktYFAcfX1x3LNlFGGlmrZHt7u9YlKExmyJdDGaTt6cMSR/A==", + "dev": true, + "requires": { + "micromark": "~2.11.0", + "micromark-extension-gfm-autolink-literal": "~0.5.0", + "micromark-extension-gfm-strikethrough": "~0.6.5", + "micromark-extension-gfm-table": "~0.4.0", + "micromark-extension-gfm-tagfilter": "~0.3.0", + "micromark-extension-gfm-task-list-item": "~0.3.0" + } + }, + "micromark-extension-gfm-autolink-literal": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-0.5.7.tgz", + "integrity": "sha512-ePiDGH0/lhcngCe8FtH4ARFoxKTUelMp4L7Gg2pujYD5CSMb9PbblnyL+AAMud/SNMyusbS2XDSiPIRcQoNFAw==", + "dev": true, + "requires": { + "micromark": "~2.11.3" + } + }, + "micromark-extension-gfm-strikethrough": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-0.6.5.tgz", + "integrity": "sha512-PpOKlgokpQRwUesRwWEp+fHjGGkZEejj83k9gU5iXCbDG+XBA92BqnRKYJdfqfkrRcZRgGuPuXb7DaK/DmxOhw==", + "dev": true, + "requires": { + "micromark": "~2.11.0" + } + }, + "micromark-extension-gfm-table": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-0.4.3.tgz", + "integrity": "sha512-hVGvESPq0fk6ALWtomcwmgLvH8ZSVpcPjzi0AjPclB9FsVRgMtGZkUcpE0zgjOCFAznKepF4z3hX8z6e3HODdA==", + "dev": true, + "requires": { + "micromark": "~2.11.0" + } + }, + "micromark-extension-gfm-tagfilter": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-0.3.0.tgz", + "integrity": "sha512-9GU0xBatryXifL//FJH+tAZ6i240xQuFrSL7mYi8f4oZSbc+NvXjkrHemeYP0+L4ZUT+Ptz3b95zhUZnMtoi/Q==", + "dev": true + }, + "micromark-extension-gfm-task-list-item": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-0.3.3.tgz", + "integrity": "sha512-0zvM5iSLKrc/NQl84pZSjGo66aTGd57C1idmlWmE87lkMcXrTxg1uXa/nXomxJytoje9trP0NDLvw4bZ/Z/XCQ==", + "dev": true, + "requires": { + "micromark": "~2.11.0" + } + }, "micromark-factory-destination": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", @@ -33196,6 +34229,27 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } } }, "miller-rabin": { @@ -33403,6 +34457,12 @@ "minimist": "^1.2.5" } }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, "mocha": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.0.3.tgz", @@ -33698,13 +34758,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", @@ -33810,12 +34863,18 @@ "dev": true }, "nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", "dev": true, "optional": true }, + "nanocolors": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/nanocolors/-/nanocolors-0.2.13.tgz", + "integrity": "sha512-0n3mSAQLPpGLV9ORXT5+C/D4mwew7Ebws69Hx4E2sgz2ZA5+32Q80B9tL8PbL7XHnRDiAxH/pnrUJ9a4fkTNTA==", + "dev": true + }, "nanoid": { "version": "3.1.23", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", @@ -33840,6 +34899,27 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } } }, "natural-compare": { @@ -33860,6 +34940,15 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, "node-gyp": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", @@ -33914,9 +35003,9 @@ } }, "node-releases": { - "version": "1.1.75", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", "dev": true }, "node-static": { @@ -34324,12 +35413,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", @@ -34362,6 +35445,43 @@ "is-descriptor": "^0.1.0" } }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -34406,6 +35526,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", @@ -34416,14 +35568,14 @@ } }, "object.values": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" + "es-abstract": "^1.19.1" } }, "omggif": { @@ -34477,9 +35629,9 @@ } }, "open-cli": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/open-cli/-/open-cli-7.0.0.tgz", - "integrity": "sha512-VxL1HWSsufFSxdcOq5Ijkd1sjK7XnmCI1QF1bYk4va3JI2nl+wLTTgOZ4i1OyNljb9rLoqajtFNCl91DmiIkQw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/open-cli/-/open-cli-7.0.1.tgz", + "integrity": "sha512-w//Mb5nLGTu9aIAsAehgxV+CGEkd+P3CbdoTW8y2coQ/fmGXBSrea0i4RBqGnd9prSPX1akrBYc0e3NnWM4SPA==", "dev": true, "requires": { "file-type": "^16.5.0", @@ -34741,6 +35893,15 @@ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -34803,9 +35964,9 @@ } }, "parse-entities": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz", - "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", "dev": true, "requires": { "character-entities": "^1.0.0", @@ -34966,10 +36127,16 @@ "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==", "dev": true }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" }, "pidtree": { "version": "0.3.1", @@ -35001,6 +36168,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", @@ -35168,10 +36372,21 @@ "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==", + "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", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", "dev": true }, "ps-tree": { @@ -35277,12 +36492,6 @@ "performance-now": "^2.1.0" } }, - "ramda": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", - "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", - "dev": true - }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -35302,6 +36511,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", @@ -35477,18 +36692,18 @@ "dev": true }, "regenerate": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", - "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "dev": true }, "regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", + "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", "dev": true, "requires": { - "regenerate": "^1.4.0" + "regenerate": "^1.4.2" } }, "regenerator-runtime": { @@ -35513,28 +36728,59 @@ "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } } }, - "regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "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": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, - "regextras": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.8.0.tgz", - "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==", + "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", + "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", + "dev": true, + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^9.0.0", + "regjsgen": "^0.5.2", + "regjsparser": "^0.7.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + } + }, "regjsgen": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", @@ -35542,9 +36788,9 @@ "dev": true }, "regjsparser": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", - "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", + "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -35558,6 +36804,12 @@ } } }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, "release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", @@ -35780,29 +37032,49 @@ } }, "remark-cli": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/remark-cli/-/remark-cli-10.0.0.tgz", - "integrity": "sha512-Yc5kLsJ5vgiQJl6xMLLJHqPac6OSAC5DOqKQrtmzJxSdJby2Jgr+OpIAkWQYwvbNHEspNagyoQnuwK2UCWg73g==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-cli/-/remark-cli-10.0.1.tgz", + "integrity": "sha512-+eln31zLE69JwBMoa8nd2sPC0DFZyiWgBrshL8aKb3L2XXTRMuEKWE/IAtNPYEtcktceAQw+OpmqVy8pAmGOwQ==", "dev": true, "requires": { "remark": "^14.0.0", "unified-args": "^9.0.0" } }, - "remark-frontmatter": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-1.3.3.tgz", - "integrity": "sha512-fM5eZPBvu2pVNoq3ZPW22q+5Ativ1oLozq2qYt9I2oNyxiUd/tDl0iLLntEVAegpZIslPWg1brhcP1VsaSVUag==", + "remark-footnotes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-3.0.0.tgz", + "integrity": "sha512-ZssAvH9FjGYlJ/PBVKdSmfyPc3Cz4rTWgZLI4iE/SX8Nt5l3o3oEjv3wwG5VD7xOjktzdwp5coac+kJV9l4jgg==", "dev": true, "requires": { - "fault": "^1.0.1", - "xtend": "^4.0.1" + "mdast-util-footnote": "^0.1.0", + "micromark-extension-footnote": "^0.3.0" + } + }, + "remark-frontmatter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-3.0.0.tgz", + "integrity": "sha512-mSuDd3svCHs+2PyO29h7iijIZx4plX0fheacJcAoYAASfgzgVIcXGYSq9GFyYocFLftQs8IOmmkgtOovs6d4oA==", + "dev": true, + "requires": { + "mdast-util-frontmatter": "^0.2.0", + "micromark-extension-frontmatter": "^0.2.0" + } + }, + "remark-gfm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-1.0.0.tgz", + "integrity": "sha512-KfexHJCiqvrdBZVbQ6RopMZGwaXz6wFJEfByIuEwGf0arvITHjiKKZ1dpXujjH9KZdm1//XJQwgfnJ3lmXaDPA==", + "dev": true, + "requires": { + "mdast-util-gfm": "^0.1.0", + "micromark-extension-gfm": "^0.3.0" } }, "remark-lint-ordered-list-marker-value": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/remark-lint-ordered-list-marker-value/-/remark-lint-ordered-list-marker-value-3.0.1.tgz", - "integrity": "sha512-02tEsP+jKxZr7zhTVTbr6sThraTsUUKCmRdONBBwAFlK3bibZJYGMukjhR7rJtCbO/uHQqGX4VhEWPcOcCoaUg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/remark-lint-ordered-list-marker-value/-/remark-lint-ordered-list-marker-value-3.1.1.tgz", + "integrity": "sha512-+bQZbo+v/A8CuLrO71gobJuKR4/sfnPgWyEggSa+zq+LXPK1HiMDjap0Wr07uYgcUXsXIPh+HD/5J5by6JL+vg==", "dev": true, "requires": { "@types/mdast": "^3.0.0", @@ -35913,26 +37185,12 @@ } }, "remark-parse": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz", - "integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz", + "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==", "dev": true, "requires": { - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^1.1.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^1.0.0", - "vfile-location": "^2.0.0", - "xtend": "^4.0.1" + "mdast-util-from-markdown": "^0.8.0" } }, "remark-stringify": { @@ -36025,9 +37283,9 @@ "dev": true }, "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true }, "repeat-string": { @@ -36036,12 +37294,6 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, - "replace-ext": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", - "dev": true - }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -36273,10 +37525,9 @@ } }, "rollup": { - "version": "2.56.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.3.tgz", - "integrity": "sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg==", - "dev": true, + "version": "2.62.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.62.0.tgz", + "integrity": "sha512-cJEQq2gwB0GWMD3rYImefQTSjrPYaC6s4J9pYqnstVLJ1CHa/aZNVkD4Epuvg4iLeMA4KRiq7UM7awKK6j7jcw==", "requires": { "fsevents": "~2.3.2" }, @@ -36285,7 +37536,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "optional": true } } @@ -36465,6 +37715,34 @@ } } }, + "rollup-plugin-html": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-html/-/rollup-plugin-html-0.2.1.tgz", + "integrity": "sha1-oYYuyoeuVLZ3aJ0NQTORHoImRj0=", + "dev": true, + "requires": { + "html-minifier": "^3.0.2", + "rollup-pluginutils": "^1.5.0" + }, + "dependencies": { + "estree-walker": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.2.1.tgz", + "integrity": "sha1-va/oCVOD2EFNXcLs9MkXO225QS4=", + "dev": true + }, + "rollup-pluginutils": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz", + "integrity": "sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg=", + "dev": true, + "requires": { + "estree-walker": "^0.2.1", + "minimatch": "^3.0.2" + } + } + } + }, "rollup-plugin-inject": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", @@ -36494,9 +37772,9 @@ } }, "rollup-plugin-polyfill-node": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-polyfill-node/-/rollup-plugin-polyfill-node-0.7.0.tgz", - "integrity": "sha512-iJLZDfvxcQh3SpC0OiYlZG9ik26aRM29hiC2sARbAPXYunB8rzW8GtVaWuJgiCtX1hNAo/OaYvVXfPp15fMs7g==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-polyfill-node/-/rollup-plugin-polyfill-node-0.8.0.tgz", + "integrity": "sha512-C4UeKedOmOBkB3FgR+z/v9kzRwV1Q/H8xWs1u1+CNe4XOV6hINfOrcO+TredKxYvopCmr+WKUSNsFUnD1RLHgQ==", "requires": { "@rollup/plugin-inject": "^4.0.0" } @@ -36671,17 +37949,6 @@ "is-extendable": "^0.1.1", "is-plain-object": "^2.0.3", "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } } }, "setprototypeof": { @@ -36846,14 +38113,62 @@ "is-descriptor": "^0.1.0" } }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true } } }, @@ -36876,35 +38191,6 @@ "requires": { "is-descriptor": "^1.0.0" } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } } } }, @@ -37166,9 +38452,9 @@ } }, "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "dev": true }, "sourcemap-codec": { @@ -37260,6 +38546,27 @@ "dev": true, "requires": { "extend-shallow": "^3.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } } }, "sprintf-js": { @@ -37299,10 +38606,130 @@ "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.13.1", - "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.13.1.tgz", - "integrity": "sha512-wZjksmjG5scEHXmV/3HWzImxNzUgaNQ6W8kkqL2GbiOldM+nqiqh7niimlC9ZGNopTGj16kheWZnZtSWgdBZNQ==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.14.0.tgz", + "integrity": "sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw==", "dev": true, "requires": { "bluebird": "3.7.2", @@ -37366,12 +38793,6 @@ } } }, - "state-toggle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", - "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==", - "dev": true - }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -37390,6 +38811,63 @@ "requires": { "is-descriptor": "^0.1.0" } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true } } }, @@ -37467,14 +38945,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": { @@ -37508,12 +39002,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": { @@ -37543,6 +39037,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", @@ -37553,15 +39053,6 @@ "peek-readable": "^3.1.4" } }, - "structured-source": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-3.0.2.tgz", - "integrity": "sha1-3YAkJeD1PcSm56yjdSkBoczaevU=", - "dev": true, - "requires": { - "boundary": "^1.0.1" - } - }, "subarg": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", @@ -37581,14 +39072,14 @@ } }, "svg-pathdata": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-5.0.5.tgz", - "integrity": "sha512-TAAvLNSE3fEhyl/Da19JWfMAdhSXTYeviXsLSoDT1UM76ADj5ndwAPX1FKQEgB/gFMPavOy6tOqfalXKUiXrow==" + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==" }, "svg2pdf.js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/svg2pdf.js/-/svg2pdf.js-2.1.0.tgz", - "integrity": "sha512-jai/P6F1IsMcoVUx9Rlnua9YHzaIjo/2enxJ+Xb5e8/m3UF5YDsFSyqIbTVoUZXgmmSI5wZWAtEz1QY4XzSPew==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/svg2pdf.js/-/svg2pdf.js-2.2.0.tgz", + "integrity": "sha512-ZmBBTUHe3vIsSEiDyadaZp0q0x+EgE8JNk7AeJsrAGOGbMntBeCcI3G0VqfWk2KtDbRHe/XoQjuudfCxq5Utzw==", "requires": { "cssesc": "^3.0.0", "font-family-papandreou": "^0.2.0-patch1", @@ -37617,23 +39108,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", @@ -37952,6 +39442,27 @@ "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } } }, "to-regex-range": { @@ -38014,9 +39525,9 @@ } }, "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true }, "token-types": { @@ -38071,24 +39582,12 @@ "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", "dev": true }, - "trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=", - "dev": true - }, "trim-newlines": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.0.2.tgz", "integrity": "sha512-GJtWyq9InR/2HRiLZgpIKv+ufIKrVrvjQWEj7PxAXNc5dwbNJkqhAUoAGgzRmULAnoOM5EIpveYd3J2VeSAIew==", "dev": true }, - "trim-trailing-lines": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", - "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==", - "dev": true - }, "trough": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", @@ -38218,6 +39717,30 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dev": true, + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "umd": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", @@ -38255,42 +39778,32 @@ "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", "dev": true }, - "unherit": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", - "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", - "dev": true, - "requires": { - "inherits": "^2.0.0", - "xtend": "^4.0.0" - } - }, "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true }, "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" } }, "unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", "dev": true }, "unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true }, "unidiff": { @@ -38311,17 +39824,31 @@ } }, "unified": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz", - "integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", + "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", "dev": true, "requires": { "bail": "^1.0.0", "extend": "^3.0.0", - "is-plain-obj": "^1.1.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", "trough": "^1.0.0", - "vfile": "^2.0.0", - "x-is-string": "^0.1.0" + "vfile": "^4.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + } } }, "unified-args": { @@ -38795,9 +40322,9 @@ } }, "unist-util-is": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", - "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", "dev": true }, "unist-util-position": { @@ -38806,43 +40333,29 @@ "integrity": "sha512-mgy/zI9fQ2HlbOtTdr2w9lhVaiFUHWQnZrFF2EUoVOqtAUdzqMtNiD99qA5a1IcjWVR8O6aVYE9u7Z2z1v0SQA==", "dev": true }, - "unist-util-remove-position": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz", - "integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==", - "dev": true, - "requires": { - "unist-util-visit": "^1.1.0" - } - }, "unist-util-stringify-position": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz", - "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==", - "dev": true - }, - "unist-util-visit": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", - "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", "dev": true, "requires": { - "unist-util-visit-parents": "^2.0.0" + "@types/unist": "^2.0.2" } }, "unist-util-visit-parents": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", - "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", "dev": true, "requires": { - "unist-util-is": "^3.0.0" + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" } }, "universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true }, "unset-value": { @@ -38897,6 +40410,12 @@ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -39046,30 +40565,33 @@ } }, "vfile": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz", - "integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", "dev": true, "requires": { - "is-buffer": "^1.1.4", - "replace-ext": "1.0.0", - "unist-util-stringify-position": "^1.0.0", - "vfile-message": "^1.0.0" + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true + } } }, - "vfile-location": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz", - "integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA==", - "dev": true - }, "vfile-message": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz", - "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", "dev": true, "requires": { - "unist-util-stringify-position": "^1.1.1" + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" } }, "vfile-reporter": { @@ -39353,6 +40875,20 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "which-typed-array": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", + "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.5", + "foreach": "^2.0.5", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.7" + } + }, "wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", @@ -39504,10 +41040,10 @@ "dev": true, "requires": {} }, - "x-is-string": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", - "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", + "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": { diff --git a/package.json b/package.json index 59c7659b..47bd07d7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svgedit", - "version": "7.0.0-beta.6", + "version": "7.1.1", "description": "Powerful SVG-Editor for your browser ", "main": "dist/Editor.js", "module": "dist/Editor.js", @@ -13,13 +13,13 @@ "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", "start": "web-dev-server --app-index src/editor/index.html --open --node-resolve", "start:test": "web-dev-server --app-index src/editor/index.html --node-resolve", - "start:watch": "web-dev-server --app-index src/editor/index.html --open --node-resolve --watch", + "start:iife": "web-dev-server --app-index dist/editor/iife-index.html --esbuild-target auto --open", "cypress:open": "run-p start cypress:open-no-start", "cypress:open-no-start": "cypress open", "cypress:run": "rimraf \".nyc_output/*\" && cypress run -q && nyc report --reporter=text-summary", @@ -63,94 +63,80 @@ }, "homepage": "https://github.com/SVG-Edit/svgedit#readme", "browserslist": [ - ">0%", - "not Opera < 59", - "not IE < 12", - "not Chrome < 75", - "not FireFox < 68", - "not Safari < 11", - "not ios_saf < 10", - "not android < 5", - "not op_mini all", - "not Edge < 18", - "not dead" + "defaults", + "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.20.4", - "canvg": "3.0.7", - "core-js": "3.16.3", - "elix": "15.0.0", - "html2canvas": "1.3.2", - "i18next": "20.4.0", - "jspdf": "2.3.1", + "browser-fs-access": "0.23.0", + "canvg": "3.0.9", + "core-js": "3.20.1", + "elix": "15.0.1", + "html2canvas": "1.3.4", + "i18next": "21.6.4", + "jspdf": "2.5.0", "pathseg": "1.2.1", "regenerator-runtime": "0.13.9", - "rollup-plugin-polyfill-node": "0.7.0", - "svg2pdf.js": "2.1.0" + "rollup-plugin-polyfill-node": "0.8.0", + "svg2pdf.js": "2.2.0" }, "devDependencies": { - "@babel/core": "7.15.0", - "@babel/preset-env": "7.15.0", - "@babel/register": "7.15.3", - "@babel/runtime-corejs3": "7.15.3", - "@cypress/code-coverage": "3.9.10", - "@cypress/fiddle": "1.19.2", - "@fintechstudios/eslint-plugin-chai-as-promised": "3.1.0", + "@babel/core": "7.16.7", + "@babel/preset-env": "7.16.7", + "@babel/register": "7.16.7", + "@babel/runtime-corejs3": "7.16.7", + "@cypress/code-coverage": "3.9.12", + "@cypress/fiddle": "1.19.3", "@rollup/plugin-babel": "5.3.0", - "@rollup/plugin-commonjs": "18.0.0", - "@rollup/plugin-dynamic-import-vars": "1.4.0", - "@rollup/plugin-node-resolve": "13.0.4", - "@rollup/plugin-replace": "3.0.0", + "@rollup/plugin-commonjs": "^18", + "@rollup/plugin-dynamic-import-vars": "1.4.2", + "@rollup/plugin-node-resolve": "13.1.1", + "@rollup/plugin-replace": "3.0.1", "@rollup/plugin-url": "6.1.0", - "@web/dev-server": "0.1.22", - "@web/dev-server-rollup": "0.3.9", - "axe-core": "4.3.3", + "@web/dev-server": "0.1.29", + "@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.16.3", + "core-js-bundle": "3.20.1", "cp-cli": "2.0.0", - "cypress": "8.3.1", - "cypress-axe": "0.13.0", + "cypress": "9.2.0", "cypress-multi-reporters": "1.5.0", "cypress-plugin-snapshots": "1.4.4", - "eslint": "7.32.0", - "eslint-config-standard": "16.0.3", - "eslint-plugin-array-func": "3.1.7", - "eslint-plugin-chai-expect": "2.2.0", - "eslint-plugin-chai-expect-keywords": "2.1.0", - "eslint-plugin-chai-friendly": "0.7.2", - "eslint-plugin-compat": "3.13.0", - "eslint-plugin-cypress": "2.11.3", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-html": "6.1.2", - "eslint-plugin-import": "2.24.2", - "eslint-plugin-jsdoc": "36.0.8", - "eslint-plugin-markdown": "2.2.0", - "eslint-plugin-no-unsanitized": "3.1.5", - "eslint-plugin-no-use-extend-native": "0.5.0", - "eslint-plugin-node": "11.1.0", - "eslint-plugin-promise": "5.1.0", - "eslint-plugin-standard": "4.1.0", "jamilih": "0.54.0", "jsdoc": "3.6.7", "node-static": "0.7.11", "npm-run-all": "4.1.5", "nyc": "15.1.0", - "open-cli": "7.0.0", + "open-cli": "7.0.1", "promise-fs": "2.1.1", "qr-manipulation": "0.7.0", "query-result": "1.0.5", - "remark-cli": "10.0.0", - "remark-lint-ordered-list-marker-value": "3.0.1", + "remark-cli": "10.0.1", + "remark-lint-ordered-list-marker-value": "3.1.1", "rimraf": "3.0.2", - "rollup": "2.56.3", + "rollup": "2.62.0", "rollup-plugin-copy": "3.4.0", "rollup-plugin-filesize": "9.1.1", + "rollup-plugin-html": "^0.2.1", "rollup-plugin-node-polyfills": "0.2.1", "rollup-plugin-progress": "1.1.2", "rollup-plugin-re": "1.0.7", "rollup-plugin-terser": "7.0.2", - "start-server-and-test": "1.13.1" + "standard": "16.0.4", + "start-server-and-test": "1.14.0" } } diff --git a/rollup.config.js b/rollup.config.js index acede78e..7f88dbfc 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -3,41 +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 dynamicImportVars from '@rollup/plugin-dynamic-import-vars'; -import { terser } from 'rollup-plugin-terser'; +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 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((nme) => path.join(source, nme)).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') -/** @todo should we support systemjs? */ -const dest = [ 'dist/editor' ]; +const dest = ['dist/editor'] // remove existing distribution -// eslint-disable-next-line no-console -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', @@ -51,6 +52,13 @@ const config = [ { sourcemap: true, file: 'dist/editor/xdomain-Editor.js', intro: 'const XDOMAIN = true;' + }, + { + file: 'dist/editor/iife-Editor.js', + format: 'iife', + inlineDynamicImports: true, + name: 'Editor', + sourcemap: true } ], plugins: [ @@ -65,9 +73,19 @@ const config = [ { dest: 'dist/editor', rename: 'xdomain-index.html', transform: (contents) => contents.toString() - .replace(' - - - - SVG-edit @@ -60,5 +27,29 @@ -->
- + + \ No newline at end of file diff --git a/src/editor/locale.js b/src/editor/locale.js index 7be840a4..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,7 +81,10 @@ export const putLocale = async function (givenParam, goodLangs) { translation: module.default } } - }); - console.info(`Lang: ${i18next.t('lang')}`); - return { langParam, i18next }; -}; + }) + return { langParam, i18next } +} + +export const t = function (key) { + return i18next.t(key) +} diff --git a/src/editor/locale/lang.af.js b/src/editor/locale/lang.af.js index 5c3b7432..a9c084b4 100644 --- a/src/editor/locale/lang.af.js +++ b/src/editor/locale/lang.af.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Verander teks inhoud', + font_family_label: 'Font:', font_family: 'Lettertipe verander Familie', font_size: 'Verandering Lettertipe Grootte', bold: 'Vetgedrukte teks', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic Text', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -202,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', @@ -287,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.ar.js b/src/editor/locale/lang.ar.js index ee393452..5cae6a49 100644 --- a/src/editor/locale/lang.ar.js +++ b/src/editor/locale/lang.ar.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'تغيير محتويات النص', + font_family_label: 'Font:', font_family: 'تغيير الخط الأسرة', font_size: 'تغيير حجم الخط', bold: 'نص جريء', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'مائل نص', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -202,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', @@ -287,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.az.js b/src/editor/locale/lang.az.js index 2d50b659..79262483 100644 --- a/src/editor/locale/lang.az.js +++ b/src/editor/locale/lang.az.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Change text contents', + font_family_label: 'Font:', font_family: 'Change Font Family', font_size: 'Change Font Size', bold: 'Bold Text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic Text', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -202,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', @@ -287,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.be.js b/src/editor/locale/lang.be.js index 64182cb7..39ccaa74 100644 --- a/src/editor/locale/lang.be.js +++ b/src/editor/locale/lang.be.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Змяненне зместу тэксту', + font_family_label: 'Font:', font_family: 'Змены Сямейства шрыфтоў', font_size: 'Змяніць памер шрыфта', bold: 'Тоўсты тэкст', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Нахілены тэкст', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -202,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', @@ -287,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.bg.js b/src/editor/locale/lang.bg.js index cae8dd2e..12316722 100644 --- a/src/editor/locale/lang.bg.js +++ b/src/editor/locale/lang.bg.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Промяна на текст съдържание', + font_family_label: 'Font:', font_family: 'Промяна на шрифта Семейство', font_size: 'Промени размера на буквите', bold: 'Получер текст', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Курсив текст', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -202,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', @@ -287,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.ca.js b/src/editor/locale/lang.ca.js index 6f56c947..a2a489cf 100644 --- a/src/editor/locale/lang.ca.js +++ b/src/editor/locale/lang.ca.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Contingut del text', + font_family_label: 'Font:', font_family: 'Canviar la font Família', font_size: 'Change Font Size', bold: 'Text en negreta', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Text en cursiva', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -205,7 +209,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 +294,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 6656a0fa..eca7726d 100644 --- a/src/editor/locale/lang.cs.js +++ b/src/editor/locale/lang.cs.js @@ -69,9 +69,13 @@ export default { straight_segments: 'úsečka', curve_segments: 'křivka', text_contents: 'Změnit text', + font_family_label: 'Font:', font_family: 'Změnit font', font_size: 'Změnit velikost písma', bold: 'Tučně', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Kurzíva', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -205,7 +209,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 +294,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 72c466e6..3b2f2974 100644 --- a/src/editor/locale/lang.cy.js +++ b/src/editor/locale/lang.cy.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Cynnwys testun Newid', + font_family_label: 'Font:', font_family: 'Newid Font Teulu', font_size: 'Newid Maint Ffont', bold: 'Testun Bras', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italig Testun', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -205,7 +209,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 +294,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..e3b5bbd1 100644 --- a/src/editor/locale/lang.da.js +++ b/src/editor/locale/lang.da.js @@ -72,6 +72,9 @@ export default { font_family: 'Skift Font Family', font_size: 'Skift skriftstørrelse', bold: 'Fed tekst', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic Text', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -205,7 +208,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 +293,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 1e78ef56..e97e3a86 100644 --- a/src/editor/locale/lang.de.js +++ b/src/editor/locale/lang.de.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Gerade', curve_segments: 'Kurve', text_contents: 'Textinhalt erstellen und bearbeiten', + font_family_label: 'Font:', font_family: 'Schriftart wählen', font_size: 'Schriftgröße einstellen', bold: 'Fetter Text', + text_decoration_underline: 'Unterstrichen', + text_decoration_linethrough: 'Durchgestrichen', + text_decoration_overline: 'Überstrichen', italic: 'Kursiver Text', text_anchor_start: 'Den Text linksbündig ausrichten', text_anchor_middle: 'Den Text zentriert ausrichten', @@ -205,7 +209,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', @@ -290,4 +294,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 fa64435c..2bb31742 100644 --- a/src/editor/locale/lang.el.js +++ b/src/editor/locale/lang.el.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Αλλαγή περιεχόμενο κειμένου', + font_family_label: 'Font:', font_family: 'Αλλαγή γραμματοσειράς Οικογένεια', font_size: 'Αλλαγή μεγέθους γραμματοσειράς', bold: 'Bold Text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Πλάγιους', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -205,7 +209,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 +294,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 93230482..7c542285 100644 --- a/src/editor/locale/lang.en.js +++ b/src/editor/locale/lang.en.js @@ -70,13 +70,33 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Change text contents', + font_family_label: 'Font:', font_family: 'Change Font Family', font_size: 'Change Font Size', - bold: 'Bold Text [B]', - italic: 'Italic Text [I]', + bold: 'Bold Text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', + italic: 'Italic Text', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', text_anchor_end: 'Align the text in end', + r_label: 'r', + x_label: 'x', + y_label: 'y', + x1_label: 'x1', + y1_label: 'y1', + x2_label: 'x2', + y2_label: 'y2', + rx_label: 'rx', + ry_label: 'ry', + cx_label: 'cx', + cy_label: 'cy', + w_label: 'w', + h_label: 'h', + id_label: 'id', + class_label: 'class', + label: 'label', class: 'Element class', serif: 'Serif', sans_serif: 'Sans-serif', @@ -129,21 +149,21 @@ export default { mode_path: 'Path Tool', mode_text: 'Text Tool', mode_image: 'Image Tool', - mode_zoom: 'Zoom Tool [Ctrl+Up/Down]', + mode_zoom: 'Zoom Tool', no_embed: 'NOTE: This image cannot be embedded. It will depend on this path to be displayed', - undo: 'Undo [Z]', - redo: 'Redo [Y]', + undo: 'Undo', + redo: 'Redo', tool_source: 'Edit Source', wireframe_mode: 'Wireframe Mode', - clone: 'Duplicate Element(s) [D]', + clone: 'Duplicate Element(s)', del: 'Delete Element(s)', - group_elements: 'Group Elements [G]', + group_elements: 'Group Elements', make_link: 'Make (hyper)link', set_link_url: 'Set link URL (leave empty to remove)', to_path: 'Convert to Path', reorient_path: 'Reorient path', ungroup: 'Ungroup Elements', - docprops: 'Document Properties [D]', + docprops: 'Document Properties', editor_homepage: 'SVG-Edit Home Page', move_bottom: 'Send to Back', move_top: 'Bring to Front', @@ -288,4 +308,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 7a65d9c5..523dcc5c 100644 --- a/src/editor/locale/lang.es.js +++ b/src/editor/locale/lang.es.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Recta', curve_segments: 'Curva', text_contents: 'Modificar el texto', + font_family_label: 'Font:', font_family: 'Tipo de fuente', font_size: 'Tamaño de la fuente', bold: 'Texto en negrita', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Texto en cursiva', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -205,7 +209,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 +294,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 e4620d74..122cab8d 100644 --- a/src/editor/locale/lang.et.js +++ b/src/editor/locale/lang.et.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Muuda teksti sisu', + font_family_label: 'Font:', font_family: 'Muutke Kirjasinperhe', font_size: 'Change font size', bold: 'Rasvane kiri', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Kursiiv', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 ce340d49..ea901618 100644 --- a/src/editor/locale/lang.fa.js +++ b/src/editor/locale/lang.fa.js @@ -69,9 +69,13 @@ export default { straight_segments: '‫مستقیم‬', curve_segments: '‫منحنی‬', text_contents: '‫تغییر محتویات متن‬', + font_family_label: 'Font:', font_family: '‫تغییر خانواده قلم‬', font_size: '‫تغییر اندازه قلم‬', bold: '‫متن توپر ‬', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: '‫متن کج ‬', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 b59302ce..7701f6ed 100644 --- a/src/editor/locale/lang.fi.js +++ b/src/editor/locale/lang.fi.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Muuta tekstin sisältö', + font_family_label: 'Font:', font_family: 'Muuta Font Family', font_size: 'Muuta fontin kokoa', bold: 'Lihavoitu teksti', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Kursivoitu', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.fr.js b/src/editor/locale/lang.fr.js index e29ca84f..3257aefa 100644 --- a/src/editor/locale/lang.fr.js +++ b/src/editor/locale/lang.fr.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Droit', curve_segments: 'Courbe', text_contents: 'Changer le contenu du texte', + font_family_label: 'Font:', font_family: 'Changer la famille de police', font_size: 'Changer la taille de la police', bold: 'Texte en gras', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Texte en italique', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 fe0a367b..f4b08d24 100644 --- a/src/editor/locale/lang.fy.js +++ b/src/editor/locale/lang.fy.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Rjocht', curve_segments: 'Bûcht', text_contents: 'Tekst oanpasse', + font_family_label: 'Font:', font_family: 'Lettertype oanpasse', font_size: 'Lettergrutte oanpasse', bold: 'Fet', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Skean', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 b0ca32b3..acdefb4c 100644 --- a/src/editor/locale/lang.ga.js +++ b/src/editor/locale/lang.ga.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Inneachar Athraigh téacs', + font_family_label: 'Font:', font_family: 'Athraigh an Cló Teaghlaigh', font_size: 'Athraigh Clómhéid', bold: 'Trom Téacs', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Iodálach Téacs', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 aa7c2e7d..1bd5d5e8 100644 --- a/src/editor/locale/lang.gl.js +++ b/src/editor/locale/lang.gl.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Cambiar o contido de texto', + font_family_label: 'Font:', font_family: 'Cambiar fonte Familia', font_size: 'Mudar tamaño de letra', bold: 'Bold Text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Texto en cursiva', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 d50591bf..c86d25a9 100755 --- a/src/editor/locale/lang.he.js +++ b/src/editor/locale/lang.he.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'שינוי תוכן טקסט', + font_family_label: 'Font:', font_family: 'שינוי גופן משפחה', font_size: 'שנה גודל גופן', bold: 'טקסט מודגש', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'טקסט נטוי', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 8446c0f7..caef85c2 100644 --- a/src/editor/locale/lang.hi.js +++ b/src/editor/locale/lang.hi.js @@ -69,9 +69,13 @@ export default { straight_segments: 'सीधे वर्ग', curve_segments: 'घुमाव', text_contents: 'बदलें पाठ सामग्री', + font_family_label: 'Font:', font_family: 'बदलें फ़ॉन्ट परिवार', font_size: 'फ़ॉन्ट का आकार बदलें', bold: 'मोटा पाठ', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'इटैलिक पाठ', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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..e2b2fa83 100644 --- a/src/editor/locale/lang.hr.js +++ b/src/editor/locale/lang.hr.js @@ -72,6 +72,9 @@ export default { font_family: 'Promjena fontova', font_size: 'Change font size', bold: 'Podebljani tekst', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic Text', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +293,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 48aed81e..c5f5d81d 100644 --- a/src/editor/locale/lang.hu.js +++ b/src/editor/locale/lang.hu.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'A szöveg tartalma', + font_family_label: 'Font:', font_family: 'Change Betűcsalád', font_size: 'Change font size', bold: 'Félkövér szöveg', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Dőlt szöveg', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 85e2e763..24847761 100644 --- a/src/editor/locale/lang.hy.js +++ b/src/editor/locale/lang.hy.js @@ -70,8 +70,12 @@ export default { curve_segments: 'Curve', text_contents: 'Change text contents', font_family: 'Change Font Family', + font_family_label: 'Font:', font_size: 'Change Font Size', bold: 'Bold Text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic Text', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.id.js b/src/editor/locale/lang.id.js index 606e3c6d..18cec39f 100644 --- a/src/editor/locale/lang.id.js +++ b/src/editor/locale/lang.id.js @@ -70,8 +70,12 @@ export default { curve_segments: 'Curve', text_contents: 'Ubah isi teks', font_family: 'Ubah Font Keluarga', + font_family_label: 'Font:', font_size: 'Ubah Ukuran Font', bold: 'Bold Teks', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic Teks', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.is.js b/src/editor/locale/lang.is.js index 018a3200..e133739f 100644 --- a/src/editor/locale/lang.is.js +++ b/src/editor/locale/lang.is.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Breyta texta innihald', + font_family_label: 'Font:', font_family: 'Change Leturfjölskylda', font_size: 'Breyta leturstærð', bold: 'Bold Text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic Text', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.it.js b/src/editor/locale/lang.it.js index b0c31bd9..6f846d2a 100644 --- a/src/editor/locale/lang.it.js +++ b/src/editor/locale/lang.it.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Linea retta', curve_segments: 'Curva', text_contents: 'Cambia il contenuto del testo', + font_family_label: 'Font:', font_family: 'Cambia il tipo di Font', font_size: 'Modifica dimensione carattere', bold: 'Grassetto', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Corsivo', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 d381f025..4983028a 100644 --- a/src/editor/locale/lang.ja.js +++ b/src/editor/locale/lang.ja.js @@ -69,9 +69,13 @@ export default { straight_segments: '直線', curve_segments: 'カーブ', text_contents: 'テキストの内容の変更', + font_family_label: 'Font:', font_family: 'フォントファミリーの変更', font_size: '文字サイズの変更', bold: '太字', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'イタリック体', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 27abf111..af1c90ff 100644 --- a/src/editor/locale/lang.ko.js +++ b/src/editor/locale/lang.ko.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: '텍스트 변경 내용', + font_family_label: 'Font:', font_family: '글꼴 변경 패밀리', font_size: '글꼴 크기 변경', bold: '굵은 텍스트', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: '기울임꼴 텍스트', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 c0aa8b12..128f9a0a 100644 --- a/src/editor/locale/lang.lt.js +++ b/src/editor/locale/lang.lt.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Keisti teksto turinys', + font_family_label: 'Font:', font_family: 'Pakeistišriftą Šeima', font_size: 'Change font size', bold: 'Pusjuodis', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Kursyvas', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.lv.js b/src/editor/locale/lang.lv.js index 671f2299..4f0d93ab 100644 --- a/src/editor/locale/lang.lv.js +++ b/src/editor/locale/lang.lv.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Mainītu teksta saturs', + font_family_label: 'Font:', font_family: 'Mainīt fonta Family', font_size: 'Mainīt fonta izmēru', bold: 'Bold Text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Kursīvs', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.mk.js b/src/editor/locale/lang.mk.js index 4e28ade6..dfe10382 100644 --- a/src/editor/locale/lang.mk.js +++ b/src/editor/locale/lang.mk.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Промена текст содржина', + font_family_label: 'Font:', font_family: 'Смени фонт Фамилија', font_size: 'Изменифонт Големина', bold: 'Задебелен текст', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic текст', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 9fc3c53e..7431710b 100644 --- a/src/editor/locale/lang.ms.js +++ b/src/editor/locale/lang.ms.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Tukar isi teks', + font_family_label: 'Font:', font_family: 'Tukar Font Keluarga', font_size: 'Ubah Saiz Font', bold: 'Bold Teks', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic Teks', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.mt.js b/src/editor/locale/lang.mt.js index 7ef159af..f1f12d8e 100644 --- a/src/editor/locale/lang.mt.js +++ b/src/editor/locale/lang.mt.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Test kontenut Bidla', + font_family_label: 'Font:', font_family: 'Bidla Font Familja', font_size: 'Change font size', bold: 'Bold Test', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Test korsiv', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.nl.js b/src/editor/locale/lang.nl.js index a489168e..cacb9dbe 100644 --- a/src/editor/locale/lang.nl.js +++ b/src/editor/locale/lang.nl.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Recht', curve_segments: 'Gebogen', text_contents: 'Wijzig tekst', + font_family_label: 'Font:', font_family: 'Verander lettertype', font_size: 'Verander lettertype grootte', bold: 'Vet', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Cursief', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 e6e3057f..e956cb42 100644 --- a/src/editor/locale/lang.no.js +++ b/src/editor/locale/lang.no.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Endre tekst innholdet', + font_family_label: 'Font:', font_family: 'Change Font Family', font_size: 'Endre skriftstørrelse', bold: 'Fet tekst', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Kursiv tekst', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.pl.js b/src/editor/locale/lang.pl.js index 98c3ffae..78b2bb9e 100644 --- a/src/editor/locale/lang.pl.js +++ b/src/editor/locale/lang.pl.js @@ -70,9 +70,13 @@ export default { straight_segments: 'Prosty', curve_segments: 'Zaokrąglony', text_contents: 'Zmień text', + font_family_label: 'Font:', font_family: 'Zmień krój czcionki', font_size: 'Zmień rozmiar czcionki', bold: 'Pogrubienie textu', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Kursywa', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -291,4 +295,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 a1ac8852..e7d0511e 100644 --- a/src/editor/locale/lang.pt-BR.js +++ b/src/editor/locale/lang.pt-BR.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Reto', curve_segments: 'Curvo', text_contents: 'Mudar conteúdo do texto', + font_family_label: 'Font:', font_family: 'Mudar o estilo da fonte', font_size: 'Mudar o tamanho da fonte', bold: 'Negrito', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italico', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 049ed220..87a3d00b 100644 --- a/src/editor/locale/lang.pt-PT.js +++ b/src/editor/locale/lang.pt-PT.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Alterar o conteúdo de texto', + font_family_label: 'Font:', font_family: 'Alterar fonte Família', font_size: 'Alterar tamanho de letra', bold: 'Bold Text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Texto em itálico', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 91d8236c..0083cad0 100644 --- a/src/editor/locale/lang.ro.js +++ b/src/editor/locale/lang.ro.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Drept', curve_segments: 'Curb', text_contents: 'Schimbarea conţinutului textului', + font_family_label: 'Font:', font_family: 'Modificare familie de fonturi', font_size: 'Schimbă dimensiunea fontului', bold: 'Text Îngroşat', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Text Înclinat', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 c0c1eb2a..820fe60f 100644 --- a/src/editor/locale/lang.ru.js +++ b/src/editor/locale/lang.ru.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Отрезок', curve_segments: 'Сплайн', text_contents: 'Изменить содержание текста', + font_family_label: 'Font:', font_family: 'Изменить семейство шрифтов', font_size: 'Изменить размер шрифта', bold: 'Жирный', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Курсив', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 c9ba63d5..6d1916f0 100644 --- a/src/editor/locale/lang.sk.js +++ b/src/editor/locale/lang.sk.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Rovný', curve_segments: 'Krivka', text_contents: 'Zmeniť text', + font_family_label: 'Font:', font_family: 'Zmeniť font', font_size: 'Zmeniť veľkosť písma', bold: 'Tučné', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Kurzíva', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 72171ae0..63eedcfe 100644 --- a/src/editor/locale/lang.sl.js +++ b/src/editor/locale/lang.sl.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Raven odsek', curve_segments: 'Ukrivljen odsek', text_contents: 'Spremeni besedilo', + font_family_label: 'Font:', font_family: 'Spremeni tip pisave', font_size: 'Spremeni velikost pisave', bold: 'Krepko', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Poševno', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 f559de7a..def95fff 100644 --- a/src/editor/locale/lang.sq.js +++ b/src/editor/locale/lang.sq.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Text contents Ndryshimi', + font_family_label: 'Font:', font_family: 'Ndryshimi Font Family', font_size: 'Ndryshimi Font Size', bold: 'Bold Text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic Text', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.sr.js b/src/editor/locale/lang.sr.js index 63b9fe7e..9ceb0c35 100644 --- a/src/editor/locale/lang.sr.js +++ b/src/editor/locale/lang.sr.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Промена садржаја текстуалне', + font_family_label: 'Font:', font_family: 'Цханге фонт породицу', font_size: 'Цханге фонт сизе', bold: 'Подебљан текст', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Италиц текст', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 4c8ab860..22e76ee0 100644 --- a/src/editor/locale/lang.sv.js +++ b/src/editor/locale/lang.sv.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Ändra textinnehållet', + font_family_label: 'Font:', font_family: 'Ändra Typsnitt', font_size: 'Ändra textstorlek', bold: 'Fet text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Kursiv text', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.sw.js b/src/editor/locale/lang.sw.js index 8987ea86..64b1748d 100644 --- a/src/editor/locale/lang.sw.js +++ b/src/editor/locale/lang.sw.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Change Nakala contents', + font_family_label: 'Font:', font_family: 'Change font Family', font_size: 'Change font Size', bold: 'Bold Nakala', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italiki Nakala', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.test.js b/src/editor/locale/lang.test.js index 45447307..bd3144fe 100644 --- a/src/editor/locale/lang.test.js +++ b/src/editor/locale/lang.test.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Change text contents', + font_family_label: 'Font:', font_family: 'Change Font Family', font_size: 'Change Font Size', bold: 'Bold Text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic Text', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.th.js b/src/editor/locale/lang.th.js index c127a5f9..99b946fa 100644 --- a/src/editor/locale/lang.th.js +++ b/src/editor/locale/lang.th.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'เปลี่ยนเนื้อหาข้อความ', + font_family_label: 'Font:', font_family: 'ครอบครัว Change Font', font_size: 'เปลี่ยนขนาดตัวอักษร', bold: 'ข้อความตัวหนา', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'ข้อความตัวเอียง', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 6140c032..42746dd2 100644 --- a/src/editor/locale/lang.tl.js +++ b/src/editor/locale/lang.tl.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Baguhin ang mga nilalaman ng teksto', + font_family_label: 'Font:', font_family: 'Baguhin ang Pamilya ng Font', font_size: 'Baguhin ang Laki ng Font', bold: 'Bold Text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic Text', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 ac1a4105..8b34c4dc 100644 --- a/src/editor/locale/lang.tr.js +++ b/src/editor/locale/lang.tr.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Değiştirmek metin içeriği', + font_family_label: 'Font:', font_family: 'Font değiştir Aile', font_size: 'Change font size', bold: 'Kalın Yazı', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italik yazı', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 de83ddb8..f7f7d0d9 100644 --- a/src/editor/locale/lang.uk.js +++ b/src/editor/locale/lang.uk.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Зміна змісту тексту', + font_family_label: 'Font:', font_family: 'Зміни Сімейство шрифтів', font_size: 'Змінити розмір шрифту', bold: 'Товстий текст', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Похилий текст', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 cc23fa2a..a38951c7 100644 --- a/src/editor/locale/lang.vi.js +++ b/src/editor/locale/lang.vi.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'Thay đổi nội dung văn bản', + font_family_label: 'Font:', font_family: 'Thay đổi Font Gia đình', font_size: 'Thay đổi cỡ chữ', bold: 'Bold Text', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'Italic Text', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -287,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.yi.js b/src/editor/locale/lang.yi.js index 1ae027b4..02bef593 100644 --- a/src/editor/locale/lang.yi.js +++ b/src/editor/locale/lang.yi.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: 'ענדערן טעקסט אינהאַלט', + font_family_label: 'Font:', font_family: 'ענדערן פאָנט פאַמילי', font_size: 'בייטן פאָנט גרייס', bold: 'דרייסט טעקסט', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: 'יטאַליק טעקסט', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 ce0c0077..8b29fdad 100644 --- a/src/editor/locale/lang.zh-CN.js +++ b/src/editor/locale/lang.zh-CN.js @@ -69,9 +69,13 @@ export default { straight_segments: '直线', curve_segments: '曲线', text_contents: '更改文本内容', + font_family_label: 'Font:', font_family: '更改字体样式', font_size: '更改字体大小', bold: '粗体', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: '斜体', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 5d235d52..03dd1f63 100644 --- a/src/editor/locale/lang.zh-HK.js +++ b/src/editor/locale/lang.zh-HK.js @@ -69,9 +69,13 @@ export default { straight_segments: 'Straight', curve_segments: 'Curve', text_contents: '更改文字内容', + font_family_label: 'Font:', font_family: '更改字体家族', font_size: '更改字体大小', bold: '粗体', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: '斜体文本', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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 7b3311f3..74a99ce7 100644 --- a/src/editor/locale/lang.zh-TW.js +++ b/src/editor/locale/lang.zh-TW.js @@ -69,9 +69,13 @@ export default { straight_segments: '直線', curve_segments: '曲線', text_contents: '更改文字內容', + font_family_label: 'Font:', font_family: '更改字體', font_size: '更改字體大小', bold: '粗體', + text_decoration_underline: 'Underline', + text_decoration_linethrough: 'Line-Through', + text_decoration_overline: 'Overline', italic: '斜體', text_anchor_start: 'Align the text in start', text_anchor_middle: 'Align the text in middle', @@ -290,4 +294,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.html b/src/editor/panels/BottomPanel.html new file mode 100644 index 00000000..85de5ce7 --- /dev/null +++ b/src/editor/panels/BottomPanel.html @@ -0,0 +1,34 @@ +
+ + + + + + + + + + + " + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/src/editor/panels/BottomPanel.js b/src/editor/panels/BottomPanel.js index 4fd14c87..cecba2ea 100644 --- a/src/editor/panels/BottomPanel.js +++ b/src/editor/panels/BottomPanel.js @@ -1,7 +1,8 @@ -import SvgCanvas from '../../svgcanvas/svgcanvas.js'; -import { jGraduate } from '../components/jgraduate/jQuery.jGraduate.js'; +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 @@ -14,99 +15,100 @@ 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) > 0.1 ? Number(value) > 0.1 : 0.1 + 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', @@ -114,130 +116,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 { imgPath } = this.editor.configObj.curConfig; + const template = document.createElement('template') + const { i18next } = this.editor - // eslint-disable-next-line no-unsanitized/property - template.innerHTML = ` -
- - -
1000
-
400
-
200
-
100
-
50
-
25
-
${i18next.t('tools.fit_to_canvas')}
-
${i18next.t('tools.fit_to_sel')}
-
${i18next.t('tools.fit_to_layer_content')}
-
${i18next.t('tools.fit_to_all')}
-
- - - - - - - ... - - - - - . - - .. - - - - - - - - - - - - - -
- `; - 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.html b/src/editor/panels/LayersPanel.html new file mode 100644 index 00000000..c6d25d27 --- /dev/null +++ b/src/editor/panels/LayersPanel.html @@ -0,0 +1,26 @@ +
+ +
+
+ +
+ + + + + + + +
+ + + + + +
Layer 1
+ + +
+
+
\ No newline at end of file diff --git a/src/editor/panels/LayersPanel.js b/src/editor/panels/LayersPanel.js index 04c59820..0230b817 100644 --- a/src/editor/panels/LayersPanel.js +++ b/src/editor/panels/LayersPanel.js @@ -1,7 +1,7 @@ -/* eslint-disable no-alert */ -import SvgCanvas from "../../svgcanvas/svgcanvas.js"; +import SvgCanvas from '../../svgcanvas/svgcanvas.js' +import LayersPanelHtml from './LayersPanel.html' -const { $id } = SvgCanvas; +const { $id } = SvgCanvas /** * @@ -10,165 +10,120 @@ class LayersPanel { /** * @param {PlainObject} editor */ - constructor(editor) { - this.updateContextPanel = editor.topPanel.updateContextPanel; - 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; - const { imgPath } = this.editor.configObj.curConfig; - // eslint-disable-next-line no-unsanitized/property - template.innerHTML = ` -
-
${i18next.t('ui.panel')}
-
-
-

${i18next.t('layers.layers')}

-
- - - - - - - -
- - - - - -
Layer 1
- ${i18next.t('layers.move_elems_to')} - -
-
-
- `; - 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); - document - .getElementById("layer_new") - .addEventListener("click", this.newLayer.bind(this)); - document - .getElementById("layer_delete") - .addEventListener("click", this.deleteLayer.bind(this)); - document - .getElementById("layer_up") - .addEventListener("click", () => this.moveLayer.bind(this)(-1)); - document - .getElementById("layer_down") - .addEventListener("click", () => this.moveLayer.bind(this)(1)); - document - .getElementById("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') } } @@ -176,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() } /** @@ -263,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) { @@ -276,88 +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) } - const selLayerNames = $id("selLayerNames"); - // empty() ref: http://youmightnotneedjquery.com/#empty - while(selLayerNames.firstChild) - selLayerNames.removeChild(selLayerNames.firstChild); - 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 = '' 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); - // eslint-disable-next-line no-unsanitized/property - selLayerNames.innerHTML += ''; + 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) // 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.html b/src/editor/panels/LeftPanel.html new file mode 100644 index 00000000..acacfacb --- /dev/null +++ b/src/editor/panels/LeftPanel.html @@ -0,0 +1,19 @@ +
+ + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/src/editor/panels/LeftPanel.js b/src/editor/panels/LeftPanel.js index 8a16642e..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 { insertChildAtIndex } from '../../svgcanvas/utilities.js'; +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,16 +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 */ - // eslint-disable-next-line class-methods-use-this - 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 } /** @@ -43,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') } } @@ -54,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') } } @@ -64,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') } } @@ -74,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') } } @@ -84,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') } } @@ -94,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') } } @@ -104,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') } } @@ -114,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') } } @@ -124,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') } } @@ -134,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') } } @@ -144,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 } } @@ -155,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() } } @@ -166,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') } } @@ -176,104 +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() { - const { i18next } = this.editor; - const { imgPath } = this.editor.configObj.curConfig; - + init () { // add Left panel - const leftMenu = [ - { - menu: ``, - position: 1 - }, - { - menu: ``, - position: 2 - }, - { - menu: ``, - position: 3 - }, - { - menu: ``, - position: 4 - }, - { - menu: ``, - position: 5 - }, - { - menu: ` - - - - `, - position: 6 - }, - { - menu: ` - - - - `, - position: 7 - }, - { - menu: ``, - position: 8 - }, - { - menu: ``, - position: 11 - } - ]; - const template = document.createElement("template"); - template.innerHTML = `
`; - this.editor.$svgEditor.append(template.content.cloneNode(true)); - const leftMenuSort = leftMenu.sort((a, b) => (a.position > b.position) ? 1 : ((b.position > a.position) ? -1 : 0)); - const parent = $id("tools_left"); - leftMenuSort.forEach(function (value) { - insertChildAtIndex(parent, value.menu, value.position); - }); + 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.html b/src/editor/panels/TopPanel.html new file mode 100644 index 00000000..89254031 --- /dev/null +++ b/src/editor/panels/TopPanel.html @@ -0,0 +1,189 @@ +
+
+
+ + +
+
+
+ + +
+ +
+
+ + +
+
+
+ + + +
+
+ + + +
+
+
+ +
+
+ + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+
+ + +
+
+
+ + + + + + + + + + + + +
+
+ + + +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + +
+ + +
+
+ +
+
+ +
+
+ +
+ +
+ +
+
+
+ +
+ + + + + + + + + +
+
+
diff --git a/src/editor/panels/TopPanel.js b/src/editor/panels/TopPanel.js index 34928a31..1e3f98df 100644 --- a/src/editor/panels/TopPanel.js +++ b/src/editor/panels/TopPanel.js @@ -1,9 +1,11 @@ +/* eslint-disable max-len */ /* globals seAlert */ -import SvgCanvas from "../../svgcanvas/svgcanvas.js"; -import { isValidUnit, getTypeMap, convertUnit } from "../../common/units.js"; +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 @@ -15,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 } /** @@ -56,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') + }) } /** @@ -79,406 +86,395 @@ 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": { - // 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"); + 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') - 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"; - - let attr = - this.selectedElement.getAttribute("stroke-linejoin") || "miter"; - - if ($id("linejoin_" + attr).length) { - this.setStrokeOpt($id("linejoin_" + attr)); - } - - attr = this.selectedElement.getAttribute("stroke-linecap") || "butt"; - - if ($id("linecap_" + attr).length) { - this.setStrokeOpt($id("linecap_" + 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; - // eslint-disable-next-line no-alert + 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' + 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; - // eslint-disable-next-line max-len - (!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").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_text_decoration_underline').pressed = this.editor.svgCanvas.hasTextDecoration('underline') + $id('tool_text_decoration_linethrough').pressed = this.editor.svgCanvas.hasTextDecoration('line-through') + $id('tool_text_decoration_overline').pressed = this.editor.svgCanvas.hasTextDecoration('overline') + $id('tool_font_family').setAttribute('value', elem.getAttribute('font-family')) + $id('tool_text_anchor').setAttribute('value', elem.getAttribute('text-anchor')) + $id('font_size').value = elem.getAttribute('font-size') + $id('text').value = elem.textContent 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)) + // if (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').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").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() } } } @@ -487,54 +483,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); - // eslint-disable-next-line max-len - (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() } } @@ -542,127 +539,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); - // eslint-disable-next-line no-alert - 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) { - // eslint-disable-next-line no-alert 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 +670,9 @@ class TopPanel { * * @returns {void} */ - deletePathNode() { + deletePathNode () { if (this.path.getNodePoint()) { - this.path.deletePathNode(); + this.path.deletePathNode() } } @@ -680,38 +680,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,476 +711,217 @@ 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 } /** * - * @param {string} value "start","end" or "middle" * @returns {false} */ - clickTextAnchor(value) { - this.editor.svgCanvas.setTextAnchor(value); - this.updateContextPanel(); - return false; + clickItalic () { + this.editor.svgCanvas.setItalic(!this.editor.svgCanvas.getItalic()) + this.updateContextPanel() + return false } + + /** + * Handles the click on the text decoration buttons + * + * @param value The text decoration value + * @returns {boolean} false + */ + clickTextDecoration (value) { + if (this.editor.svgCanvas.hasTextDecoration(value)) { + this.editor.svgCanvas.removeTextDecoration(value) + } else { + this.editor.svgCanvas.addTextDecoration(value) + } + this.updateContextPanel() + return false + } + + /** + * Sets the text anchor value + * + * @returns {false} + */ + clickTextAnchor (evt) { + this.editor.svgCanvas.setTextAnchor(evt.detail.value) + 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.getSelectedElems(), true); + editor.svgCanvas.setMode('select') + editor.svgCanvas.selectOnly(editor.svgCanvas.getSelectedElements(), true) }, (error) => { - // eslint-disable-next-line no-console - console.log("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) { - const { imgPath } = this.editor.configObj.curConfig; + 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', `${imgPath}/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', `${imgPath}/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; - const { imgPath } = this.editor.configObj.curConfig; - // eslint-disable-next-line no-unsanitized/property - template.innerHTML = ` -
-
-
- - -
-
-
- - -
- -
-
- - -
-
-
- - -
-
- - - -
-
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - -
- -
-
- - -
-
-
- - - - - - - - - - - ${i18next.t('tools.selected_objects')} - ${i18next.t('tools.largest_object')} - ${i18next.t('tools.smallest_object')} - ${i18next.t('tools.page')} - -
-
- - - - - -
-
- - - -
-
- -
-
- - -
-
- -
-
- - - - -
-
- - - - -
-
- - - - - - - - -
-
- - - - ${i18next.t('properties.serif')} - ${i18next.t('properties.sans_serif')} - ${i18next.t('properties.cursive')} - ${i18next.t('properties.fantasy')} - ${i18next.t('properties.monospace')} - ${i18next.t('properties.courier')} - ${i18next.t('properties.helvetica')} - ${i18next.t('properties.times')} - - -
-
- - - -
- - -
-
- -
-
- - -
-
- - -
- -
- -
-
-
- - -
- - - - - - - - - - -
-
-
- `; - 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); + '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_decoration_underline').addEventListener('click', () => this.clickTextDecoration.bind(this)('underline')) + $id('tool_text_decoration_linethrough').addEventListener('click', () => this.clickTextDecoration.bind(this)('line-through')) + $id('tool_text_decoration_overline').addEventListener('click', () => this.clickTextDecoration.bind(this)('overline')) + $id('tool_text_anchor').addEventListener('change', (evt) => this.clickTextAnchor.bind(this)(evt)) + $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_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/svgedit.css b/src/editor/svgedit.css index 510b5974..b409c9b5 100644 --- a/src/editor/svgedit.css +++ b/src/editor/svgedit.css @@ -18,12 +18,12 @@ .svg_editor { display: grid; grid-template-rows: auto 15px 1fr 40px; - grid-template-columns: 34px 15px 1fr 15px; + grid-template-columns: 40px 15px 50px 1fr 15px; grid-template-areas: - "top top top top" - "left corner rulerX side" - "left rulerY workarea side" - "left bottom bottom bottom"; + "main main main top top" + "left corner rulerX rulerX side" + "left rulerY workarea workarea side" + "left bottom bottom bottom bottom"; font-size: 8pt; background: var(--main-bg-color); font-family: Verdana, Helvetica, Arial; @@ -33,18 +33,18 @@ height: 100%; } -.svg_editor.open { - grid-template-columns: 34px 15px 1fr 150px; -} - /* on smaller screen, allow 2 lines for the toolbar */ - @media screen and (max-width:1250px) { .svg_editor { grid-template-rows: minmax(80px, auto) 15px 1fr 40px; } } +/* class to open the right panel */ +.svg_editor.open { + grid-template-columns: 34px 15px 50px 1fr 150px; +} + #svgroot { user-select: none; position: absolute; @@ -167,7 +167,6 @@ hr { #layerlist td.layername:hover { color: blue; - font-style: italic; } #layerlist tr.layersel td.layername { @@ -186,6 +185,7 @@ hr { —————————————————————————————*/ #main_button { + grid-area: main; color: #fff; border-radius: 3px; padding-block: 2px; @@ -299,8 +299,7 @@ hr { display: flex; flex-direction: row; flex-wrap: wrap; - /* leave space for the main menu */ - position: relative; + align-items: flex-start; background-color: var(--main-bg-color); } @@ -318,31 +317,35 @@ hr { overflow: auto; display: flex; align-items: center; - scrollbar-width: thin; + scrollbar-width: thin; /* Firefox */ } -#tools_bottom ::-webkit-scrollbar { +#tools_bottom ::-webkit-scrollbar { /* Chrome, Edge, and Safari */ width: 3px; } -#tools_bottom se-list { +#tools_bottom se-list, #tools_bottom se-select { margin-bottom: 8px; } +#zoom { + color: var(--text-color); + background-color: var(--main-bg-color); + border: none; +} /*—————————————————————————————*/ #tools_left { grid-area: left; border-right: none; + margin-left: auto; + margin-right: auto; overflow-y: scroll; - /* Works on Firefox */ - scrollbar-width: 3px; - scrollbar-color: rgb(70, 70, 70) auto; + scrollbar-width: none; /* Firefox */ } -/* Scrollbar styling on Chrome, Edge, and Safari */ -#tools_left::-webkit-scrollbar { +#tools_left::-webkit-scrollbar { /* Chrome, Edge, and Safari */ width: 3px; } @@ -379,17 +382,13 @@ hr { } #cur_context_panel { - position: absolute; - top: 57px; - left: 56px; + grid-area: rulerX; line-height: 22px; overflow: auto; padding-left: 5px; font-size: 12px; background: rgba(0, 0, 0, 0.8); color: #ccc; - padding: 0 10px; - border-radius: 0 0 3px 0; } #cur_context_panel a { diff --git a/src/editor/templates/editorTemplate.html b/src/editor/templates/editorTemplate.html new file mode 100644 index 00000000..59cb1a80 --- /dev/null +++ b/src/editor/templates/editorTemplate.html @@ -0,0 +1,5 @@ +
+
+
+
+
\ No newline at end of file diff --git a/src/editor/templates/editorTemplate.js b/src/editor/templates/editorTemplate.js deleted file mode 100644 index 6d808ac9..00000000 --- a/src/editor/templates/editorTemplate.js +++ /dev/null @@ -1,11 +0,0 @@ -const editorTemplate = document.createElement('template'); - -editorTemplate.innerHTML = ` -
-
-
-
-
-`; - -export default editorTemplate; diff --git a/src/editor/templates/rulersTemplate.html b/src/editor/templates/rulersTemplate.html new file mode 100644 index 00000000..63b9ae4c --- /dev/null +++ b/src/editor/templates/rulersTemplate.html @@ -0,0 +1,45 @@ + +
+
+
+ +
+
+
+
+ +
+
\ No newline at end of file diff --git a/src/editor/templates/rulersTemplate.js b/src/editor/templates/rulersTemplate.js deleted file mode 100644 index e833cc56..00000000 --- a/src/editor/templates/rulersTemplate.js +++ /dev/null @@ -1,52 +0,0 @@ -const rulersTemplate = document.createElement('template'); - -rulersTemplate.innerHTML = ` - -
-
-
- -
-
-
-
- -
-
-`; - -export default rulersTemplate; 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 f3208c01..8cd945f9 100644 --- a/src/svgcanvas/blur-event.js +++ b/src/svgcanvas/blur-event.js @@ -4,22 +4,17 @@ * @license MIT * @copyright 2011 Jeff Schiller */ -import * as hstry from './history.js'; -const { - InsertElementCommand, ChangeElementCommand, BatchCommand -} = hstry; - -let blurContext_ = null; +let svgCanvas = null /** * @function module:blur.init * @param {module:blur.blurContext} blurContext * @returns {void} */ -export const init = function (blurContext) { - blurContext_ = blurContext; -}; +export const init = (canvas) => { + svgCanvas = canvas +} /** * Sets the `stdDeviation` blur value on the selected element without being undoable. @@ -28,42 +23,37 @@ export const init = function (blurContext) { * @returns {void} */ export const setBlurNoUndo = function (val) { - const selectedElements = blurContext_.getSelectedElements(); - if (!blurContext_.getFilter()) { - blurContext_.getCanvas().setBlur(val); - return; + const selectedElements = svgCanvas.getSelectedElements() + if (!svgCanvas.getFilter()) { + 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" - blurContext_.changeSelectedAttributeNoUndoMethod('filter', ''); - blurContext_.setFilterHidden(true); + svgCanvas.changeSelectedAttributeNoUndo('filter', '') + svgCanvas.setFilterHidden(true) } else { - const elem = selectedElements[0]; - if (blurContext_.getFilterHidden()) { - blurContext_.changeSelectedAttributeNoUndoMethod('filter', 'url(#' + elem.id + '_blur)'); + const elem = selectedElements[0] + if (svgCanvas.getFilterHidden()) { + svgCanvas.changeSelectedAttributeNoUndo('filter', 'url(#' + elem.id + '_blur)') } - if (blurContext_.isWebkit()) { - // console.log('e', elem); - elem.removeAttribute('filter'); - elem.setAttribute('filter', 'url(#' + elem.id + '_blur)'); - } - const filter = blurContext_.getFilter(); - blurContext_.changeSelectedAttributeNoUndoMethod('stdDeviation', val, [ filter.firstChild ]); - blurContext_.getCanvas().setBlurOffsets(filter, val); + const filter = svgCanvas.getFilter() + svgCanvas.changeSelectedAttributeNoUndo('stdDeviation', val, [filter.firstChild]) + svgCanvas.setBlurOffsets(filter, val) } -}; +} /** * * @returns {void} */ function finishChange () { - const bCmd = blurContext_.getCanvas().undoMgr.finishUndoableChange(); - blurContext_.getCurCommand().addSubCommand(bCmd); - blurContext_.addCommandToHistory(blurContext_.getCurCommand()); - blurContext_.setCurCommand(null); - blurContext_.setFilter(null); + const bCmd = svgCanvas.undoMgr.finishUndoableChange() + svgCanvas.getCurCommand().addSubCommand(bCmd) + svgCanvas.addCommandToHistory(svgCanvas.getCurCommand()) + svgCanvas.setCurCommand(null) + svgCanvas.setFilter(null) } /** @@ -77,20 +67,19 @@ function finishChange () { export const setBlurOffsets = function (filterElem, stdDev) { if (stdDev > 3) { // TODO: Create algorithm here where size is based on expected blur - blurContext_.getCanvas().assignAttributes(filterElem, { + svgCanvas.assignAttributes(filterElem, { x: '-50%', y: '-50%', width: '200%', height: '200%' - }, 100); - // Removing these attributes hides text in Chrome (see Issue 579) - } else if (!blurContext_.isWebkit()) { - filterElem.removeAttribute('x'); - filterElem.removeAttribute('y'); - filterElem.removeAttribute('width'); - filterElem.removeAttribute('height'); + }, 100) + } else { + filterElem.removeAttribute('x') + filterElem.removeAttribute('y') + filterElem.removeAttribute('width') + filterElem.removeAttribute('height') } -}; +} /** * Adds/updates the blur filter to the selected element. @@ -100,62 +89,68 @@ export const setBlurOffsets = function (filterElem, stdDev) { * @returns {void} */ export const setBlur = function (val, complete) { - const selectedElements = blurContext_.getSelectedElements(); - if (blurContext_.getCurCommand()) { - finishChange(); - return; + const { + InsertElementCommand, ChangeElementCommand, BatchCommand + } = svgCanvas.history + + const selectedElements = svgCanvas.getSelectedElements() + if (svgCanvas.getCurCommand()) { + finishChange() + return } // Looks for associated blur, creates one if not found - const elem = selectedElements[0]; - const elemId = elem.id; - blurContext_.setFilter(blurContext_.getCanvas().getElem(elemId + '_blur')); + const elem = selectedElements[0] + const elemId = elem.id + svgCanvas.setFilter(svgCanvas.getElement(elemId + '_blur')) - val -= 0; + val -= 0 - const batchCmd = new BatchCommand(); + const batchCmd = new BatchCommand() // Blur found! - if (blurContext_.getFilter()) { + if (svgCanvas.getFilter()) { if (val === 0) { - blurContext_.setFilter(null); + svgCanvas.setFilter(null) } } else { // Not found, so create - const newblur = blurContext_.getCanvas().addSVGElementFromJson({ element: 'feGaussianBlur', + const newblur = svgCanvas.addSVGElementsFromJson({ + element: 'feGaussianBlur', attr: { in: 'SourceGraphic', stdDeviation: val } - }); + }) - blurContext_.setFilter(blurContext_.getCanvas().addSVGElementFromJson({ element: 'filter', + svgCanvas.setFilter(svgCanvas.addSVGElementsFromJson({ + element: 'filter', attr: { id: elemId + '_blur' } - })); - blurContext_.getFilter().append(newblur); - blurContext_.getCanvas().findDefs().append(blurContext_.getFilter()); + })) + svgCanvas.getFilter().append(newblur) + svgCanvas.findDefs().append(svgCanvas.getFilter()) - batchCmd.addSubCommand(new InsertElementCommand(blurContext_.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 } - blurContext_.changeSelectedAttributeMethod('filter', 'url(#' + elemId + '_blur)'); - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - blurContext_.getCanvas().setBlurOffsets(blurContext_.getFilter(), val); - const filter = blurContext_.getFilter(); - blurContext_.setCurCommand(batchCmd); - blurContext_.getCanvas().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) { - blurContext_.getCanvas().setBlurNoUndo(val); - finishChange(); + svgCanvas.setBlurNoUndo(val) + finishChange() } -}; +} diff --git a/src/svgcanvas/clear.js b/src/svgcanvas/clear.js index bf8e190a..5fc186bf 100644 --- a/src/svgcanvas/clear.js +++ b/src/svgcanvas/clear.js @@ -4,41 +4,40 @@ * @license MIT * @copyright 2011 Jeff Schiller */ -import { NS } from '../common/namespaces.js'; +import { NS } from './namespaces.js' -let clearContext_ = null; +let svgCanvas = null /** * @function module:clear.init * @param {module:clear.SvgCanvas#init} clearContext * @returns {void} */ -export const init = function (clearContext) { - clearContext_ = clearContext; -}; +export const init = (canvas) => { + svgCanvas = canvas +} -export const clearSvgContentElementInit = function () { - const curConfig = clearContext_.getCurConfig(); - const { dimensions } = curConfig; - const el = clearContext_.getSVGContent(); - // empty() - while(el.firstChild) - el.removeChild(el.firstChild); +export const clearSvgContentElementInit = () => { + const curConfig = svgCanvas.getCurConfig() + const { dimensions } = curConfig + const el = svgCanvas.getSvgContent() + // empty + while (el.firstChild) { el.removeChild(el.firstChild) } // TODO: Clear out all other attributes first? - const pel = clearContext_.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 = clearContext_.getDOMDocument().createComment(' Created with SVG-edit - https://github.com/SVG-Edit/svgedit'); - clearContext_.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 7d63f49f..1b984514 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 @@ -25,278 +25,274 @@ const pathMap = [ * @returns {boolean} */ /** - * @function module:coords.EditorContext#getDrawing - * @returns {module:draw.Drawing} -*/ -/** - * @function module:coords.EditorContext#getSVGRoot + * @function module:coords.EditorContext#getSvgRoot * @returns {SVGSVGElement} */ -let editorContext_ = null; +let svgCanvas = null /** * @function module:coords.init * @param {module:svgcanvas.SvgCanvas#event:pointsAdded} editorContext * @returns {void} */ -export const init = function (editorContext) { - editorContext_ = editorContext; -}; +export const init = (canvas) => { + svgCanvas = canvas +} /** * Applies coordinate changes to an element based on the given matrix. * @name module:coords.remapElement * @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 = editorContext_.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg'; +export const remapElement = (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 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); - if (attrVal && attrVal.startsWith('url(') && (m.a < 0 || m.d < 0)) { - const grad = getRefElem(attrVal); - const newgrad = grad.cloneNode(true); + ['fill', 'stroke'].forEach((type) => { + const attrVal = selected.getAttribute(type) + if (attrVal?.startsWith('url(') && (m.a < 0 || m.d < 0)) { + 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 = editorContext_.getDrawing().getNextId(); - findDefs().append(newgrad); - selected.setAttribute(type, 'url(#' + newgrad.id + ')'); + newgrad.id = svgCanvas.getCurrentDrawing().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 = editorContext_.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 = editorContext_.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 = editorContext_.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 b1eeacc4..7fcc0e14 100644 --- a/src/svgcanvas/copy-elem.js +++ b/src/svgcanvas/copy-elem.js @@ -1,6 +1,4 @@ -import { isWebkit } from '../common/browser.js'; -import { convertPath } from './path.js'; -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. @@ -11,44 +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(); - - // Opera's "d" value needs to be reset for Opera/Win/non-EN - // Also needed for webkit (else does not keep curved segments on clone) - if (isWebkit() && el.nodeName === 'path') { - const fixedD = convertPath(el); - newEl.setAttribute('d', fixedD); - } + 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 new file mode 100644 index 00000000..8079ec02 --- /dev/null +++ b/src/svgcanvas/dataStorage.js @@ -0,0 +1,28 @@ +/** A storage solution aimed at replacing jQuerys data function. +* Implementation Note: Elements are stored in a (WeakMap)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap]. +* This makes sure the data is garbage collected when the node is removed. +*/ +const dataStorage = { + _storage: new WeakMap(), + put: function (element, key, obj) { + if (!this._storage.has(element)) { + this._storage.set(element, new Map()) + } + this._storage.get(element).set(key, obj) + }, + get: function (element, key) { + return this._storage.get(element)?.get(key) + }, + has: function (element, key) { + return this._storage.has(element) && this._storage.get(element).has(key) + }, + remove: function (element, key) { + const ret = this._storage.get(element).delete(key) + if (this._storage.get(element).size === 0) { + this._storage.delete(element) + } + return ret + } +} + +export default dataStorage diff --git a/src/svgcanvas/draw.js b/src/svgcanvas/draw.js index 01806af2..0faf6d77 100644 --- a/src/svgcanvas/draw.js +++ b/src/svgcanvas/draw.js @@ -5,31 +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 '../common/namespaces.js'; +import { NS } from './namespaces.js' import { - toXml, getElem -} from './utilities.js'; + toXml, getElement +} from './utilities.js' import { copyElem as utilCopyElem -} from './copy-elem.js'; -import { - BatchCommand, RemoveElementCommand, MoveElementCommand, ChangeElementCommand -} from './history.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. @@ -37,7 +34,7 @@ let disabledElems = []; * @returns {module:history.HistoryRecordingService} */ function historyRecordingService (hrService) { - return hrService || new HistoryRecordingService(canvas_.undoMgr); + return hrService || new HistoryRecordingService(svgCanvas.undoMgr) } /** @@ -46,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 : '' } /** @@ -56,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 } /** @@ -76,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 @@ -109,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. @@ -119,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)) } } @@ -149,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_ } /** @@ -174,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 } /** @@ -186,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_ = '' } /** @@ -196,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 } /** @@ -204,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 } /** @@ -244,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 } /** @@ -268,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 } /** @@ -277,7 +274,7 @@ export class Drawing { * @returns {boolean} */ hasLayer (name) { - return this.layer_map[name] !== undefined; + return this.layer_map[name] !== undefined } /** @@ -286,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 } /** @@ -302,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 } /** @@ -312,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() : '' } /** @@ -322,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 } /** @@ -340,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 } /** @@ -384,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() } /** @@ -425,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() } /** @@ -442,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 } /** @@ -462,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 } /** @@ -475,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?.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 } /** @@ -527,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() } /** @@ -557,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 } /** @@ -601,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 } /** @@ -616,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() } /** @@ -631,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() } /** @@ -650,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) } } @@ -664,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) } } @@ -681,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 @@ -720,7 +717,7 @@ export const randomizeIds = function (enableRandomization, currentDrawing) { * @returns {Element[]} the array with selected DOM elements */ /** - * @function module:draw.DrawCanvasInit#getSVGContent + * @function module:draw.DrawCanvasInit#getSvgContent * @returns {SVGSVGElement} */ /** @@ -747,19 +744,19 @@ export const randomizeIds = function (enableRandomization, currentDrawing) { * @returns {void} */ /** - * @function module:draw.DrawCanvasInit#changeSVGContent + * @function module:draw.DrawCanvasInit#changeSvgContent * @returns {void} */ -let canvas_; +let svgCanvas /** * @function module:draw.init * @param {module:draw.DrawCanvasInit} canvas * @returns {void} */ -export const init = function (canvas) { - canvas_ = canvas; -}; +export const init = (canvas) => { + svgCanvas = canvas +} /** * Updates layer system. @@ -767,9 +764,9 @@ export const init = function (canvas) { * @returns {void} */ export const identifyLayers = function () { - leaveContext(); - canvas_.getCurrentDrawing().identifyLayers(); -}; + leaveContext() + svgCanvas.getCurrentDrawing().identifyLayers() +} /** * Creates a new top-level layer in the drawing with the given name, sets the current layer @@ -782,13 +779,13 @@ export const identifyLayers = function () { * @returns {void} */ export const createLayer = function (name, hrService) { - const newLayer = canvas_.getCurrentDrawing().createLayer( + const newLayer = svgCanvas.getCurrentDrawing().createLayer( name, historyRecordingService(hrService) - ); - canvas_.clearSelection(); - canvas_.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 @@ -802,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 = canvas_.getCurrentDrawing().cloneLayer(name, historyRecordingService(hrService)); + const newLayer = svgCanvas.getCurrentDrawing().cloneLayer(name, historyRecordingService(hrService)) - canvas_.clearSelection(); - leaveContext(); - canvas_.call('changed', [ newLayer ]); -}; + svgCanvas.clearSelection() + leaveContext() + svgCanvas.call('changed', [newLayer]) +} /** * Deletes the current layer from the drawing and then clears the selection. This function @@ -817,21 +814,22 @@ export const cloneLayer = function (name, hrService) { * @returns {boolean} `true` if an old layer group was found to delete */ export const deleteCurrentLayer = function () { - let currentLayer = canvas_.getCurrentDrawing().getCurrentLayer(); - const { nextSibling } = currentLayer; - const parent = currentLayer.parentNode; - currentLayer = canvas_.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)); - canvas_.addCommandToHistory(batchCmd); - canvas_.clearSelection(); - canvas_.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 @@ -841,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 = canvas_.getCurrentDrawing().setCurrentLayer(toXml(name)); + const result = svgCanvas.getCurrentDrawing().setCurrentLayer(toXml(name)) if (result) { - canvas_.clearSelection(); + svgCanvas.clearSelection() } - return result; -}; + return result +} /** * Renames the current layer. If the layer name is not valid (i.e. unique), then this function @@ -858,17 +856,17 @@ export const setCurrentLayer = function (name) { * @returns {boolean} Whether the rename succeeded */ export const renameCurrentLayer = function (newName) { - const drawing = canvas_.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) { - canvas_.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, @@ -880,14 +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 drawing = canvas_.getCurrentDrawing(); - const result = drawing.setCurrentLayerPosition(newPos); + const { MoveElementCommand } = svgCanvas.history + const drawing = svgCanvas.getCurrentDrawing() + const result = drawing.setCurrentLayerPosition(newPos) if (result) { - canvas_.addCommandToHistory(new MoveElementCommand(result.currentGroup, result.oldNextSibling, canvas_.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 @@ -898,23 +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 drawing = canvas_.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'; - canvas_.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()) { - canvas_.clearSelection(); - canvas_.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,30 +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 // find the layer - const drawing = canvas_.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 = canvas_.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)) } - canvas_.addCommandToHistory(batchCmd); + svgCanvas.addCommandToHistory(batchCmd) - return true; -}; + return true +} /** * @function module:draw.mergeLayer @@ -955,11 +956,11 @@ export const moveSelectedToLayer = function (layerName) { * @returns {void} */ export const mergeLayer = function (hrService) { - canvas_.getCurrentDrawing().mergeLayer(historyRecordingService(hrService)); - canvas_.clearSelection(); - leaveContext(); - canvas_.changeSVGContent(); -}; + svgCanvas.getCurrentDrawing().mergeLayer(historyRecordingService(hrService)) + svgCanvas.clearSelection() + leaveContext() + svgCanvas.changeSvgContent() +} /** * @function module:draw.mergeAllLayers @@ -967,11 +968,11 @@ export const mergeLayer = function (hrService) { * @returns {void} */ export const mergeAllLayers = function (hrService) { - canvas_.getCurrentDrawing().mergeAllLayers(historyRecordingService(hrService)); - canvas_.clearSelection(); - leaveContext(); - canvas_.changeSVGContent(); -}; + svgCanvas.getCurrentDrawing().mergeAllLayers(historyRecordingService(hrService)) + svgCanvas.clearSelection() + leaveContext() + svgCanvas.changeSvgContent() +} /** * Return from a group context to the regular kind, make any previously @@ -981,25 +982,25 @@ export const mergeAllLayers = function (hrService) { * @returns {void} */ export const leaveContext = function () { - const len = disabledElems.length; - const dataStorage = canvas_.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 = []; - canvas_.clearSelection(true); - canvas_.call('contextset', null); + disabledElems = [] + svgCanvas.clearSelection(true) + svgCanvas.call('contextset', null) } - canvas_.setCurrentGroup(null); -}; + svgCanvas.setCurrentGroup(null) +} /** * Set the current context (for in-group editing). @@ -1009,42 +1010,42 @@ export const leaveContext = function () { * @returns {void} */ export const setContext = function (elem) { - const dataStorage = canvas_.getDataStorage(); - leaveContext(); + const dataStorage = svgCanvas.getDataStorage() + leaveContext() if (typeof elem === 'string') { - elem = getElem(elem); + elem = getElement(elem) } // Edit inside this group - canvas_.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); - }); - canvas_.clearSelection(); - canvas_.call('contextset', canvas_.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 41b77216..28a9a7ce 100644 --- a/src/svgcanvas/elem-get-set.js +++ b/src/svgcanvas/elem-get-set.js @@ -4,49 +4,43 @@ * @copyright 2011 Jeff Schiller */ -import { jGraduate } from '../editor/components/jgraduate/jQuery.jGraduate.js'; -import * as hstry from './history.js'; -import { NS } from '../common/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'; + walkTree, getHref, setHref, getElement +} 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' -const { - InsertElementCommand, RemoveElementCommand, - ChangeElementCommand, BatchCommand -} = hstry; - -let elemContext_ = null; +let svgCanvas = null /** * @function module:elem-get-set.init * @param {module:elem-get-set.elemContext} elemContext * @returns {void} */ -export const init = function (elemContext) { - elemContext_ = elemContext; -}; +export const init = (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 currentZoom = elemContext_.getCurrentZoom(); - const w = elemContext_.getSVGContent().getAttribute('width') / currentZoom; - const h = elemContext_.getSVGContent().getAttribute('height') / currentZoom; +export const getResolutionMethod = () => { + const zoom = svgCanvas.getZoom() + const w = svgCanvas.getSvgContent().getAttribute('width') / zoom + const h = svgCanvas.getSvgContent().getAttribute('height') / zoom return { w, h, - zoom: currentZoom - }; -}; + zoom + } +} /** * @function module:elem-get-set.SvgCanvas#getTitle @@ -54,24 +48,24 @@ export const getResolutionMethod = function () { * @returns {string|void} the current group/SVG's title contents or * `undefined` if no element is passed nd there are no selected elements. */ -export const getTitleMethod = function (elem) { - const selectedElements = elemContext_.getSelectedElements(); - const dataStorage = elemContext_.getDataStorage(); - elem = elem || selectedElements[0]; - if (!elem) { return undefined; } +export const getTitleMethod = (elem) => { + 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. @@ -80,39 +74,43 @@ export const getTitleMethod = function (elem) { * @todo Combine this with `setDocumentTitle` * @returns {void} */ -export const setGroupTitleMethod = function (val) { - const selectedElements = elemContext_.getSelectedElements(); - const dataStorage = elemContext_.getDataStorage(); - let elem = selectedElements[0]; +export const setGroupTitleMethod = (val) => { + const { + InsertElementCommand, RemoveElementCommand, + ChangeElementCommand, BatchCommand + } = 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; - if (!val.length) { + let title + if (val.length === 0) { // 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 = elemContext_.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)) } - elemContext_.addCommandToHistory(batchCmd); -}; + svgCanvas.addCommandToHistory(batchCmd) +} /** * Adds/updates a title element for the document with the given name. @@ -121,34 +119,35 @@ export const setGroupTitleMethod = function (val) { * @param {string} newTitle - String with the new title * @returns {void} */ -export const setDocumentTitleMethod = function (newTitle) { - const childs = elemContext_.getSVGContent().childNodes; - let docTitle = false; let oldTitle = ''; +export const setDocumentTitleMethod = (newTitle) => { + 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 = elemContext_.getDOMDocument().createElementNS(NS.SVG, 'title'); - elemContext_.getSVGContent().insertBefore(docTitle, elemContext_.getSVGContent().firstChild); - // svgcontent.firstChild.before(docTitle); // Ok to replace above with this? + 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 })); - elemContext_.addCommandToHistory(batchCmd); -}; + batchCmd.addSubCommand(new ChangeElementCommand(docTitle, { '#text': oldTitle })) + svgCanvas.addCommandToHistory(batchCmd) +} /** * Changes the document's dimensions to the given size. @@ -160,59 +159,60 @@ export const setDocumentTitleMethod = function (newTitle) { * @returns {boolean} Indicates if resolution change was successful. * It will fail on "fit to content" option with no content to fit to. */ -export const setResolutionMethod = function (x, y) { - const currentZoom = elemContext_.getCurrentZoom(); - const res = elemContext_.getCanvas().getResolution(); - const { w, h } = res; - let batchCmd; +export const setResolutionMethod = (x, y) => { + 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(); - elemContext_.getCanvas().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((_item, _i) => { + dx.push(bbox.x * -1) + dy.push(bbox.y * -1) + }) - const cmd = elemContext_.getCanvas().moveSelectedElements(dx, dy, true); - batchCmd.addSubCommand(cmd); - elemContext_.getCanvas().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) - elemContext_.getSVGContent().setAttribute('width', x); - elemContext_.getSVGContent().setAttribute('height', y); + svgCanvas.getSvgContent().setAttribute('width', x) + svgCanvas.getSvgContent().setAttribute('height', y) - this.contentW = x; - this.contentH = y; - batchCmd.addSubCommand(new ChangeElementCommand(elemContext_.getSVGContent(), { width: w, height: h })); + svgCanvas.contentW = x + svgCanvas.contentH = y + batchCmd.addSubCommand(new ChangeElementCommand(svgCanvas.getSvgContent(), { width: w, height: h })) - elemContext_.getSVGContent().setAttribute('viewBox', [ 0, 0, x / currentZoom, y / currentZoom ].join(' ')); - batchCmd.addSubCommand(new ChangeElementCommand(elemContext_.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(' ') })) - elemContext_.addCommandToHistory(batchCmd); - elemContext_.call('changed', [ elemContext_.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. @@ -220,12 +220,12 @@ export const setResolutionMethod = function (x, y) { * @param {boolean} [add] - Indicates whether or not to add the namespace value * @returns {string} The editor's namespace URL */ -export const getEditorNSMethod = function (add) { +export const getEditorNSMethod = (add) => { if (add) { - elemContext_.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 @@ -240,57 +240,57 @@ export const getEditorNSMethod = function (add) { * @param {Integer} editorH - The editor's workarea box's height * @returns {module:elem-get-set.ZoomAndBBox|void} */ -export const setBBoxZoomMethod = function (val, editorW, editorH) { - const currentZoom = elemContext_.getCurrentZoom(); - const selectedElements = elemContext_.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); - elemContext_.getCanvas().setZoom(zoom); - return { zoom, bbox: bb }; - }; +export const setBBoxZoomMethod = (val, editorW, editorH) => { + const zoom = svgCanvas.getZoom() + const selectedElements = svgCanvas.getSelectedElements() + let spacer = 0.85 + let bb + const calcZoom = (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 : currentZoom * bb.factor; - elemContext_.getCanvas().setZoom(newzoom); - return { zoom: currentZoom, 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 = elemContext_.getCanvas().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(elemContext_.getCanvas().getCurrentDrawing().getCurrentLayer())); - break; - default: - return undefined; + case 'selection': { + if (!selectedElements[0]) { return undefined } + const selectedElems = selectedElements.map((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. @@ -299,18 +299,18 @@ export const setBBoxZoomMethod = function (val, editorW, editorH) { * @fires module:elem-get-set.SvgCanvas#event:ext_zoomChanged * @returns {void} */ -export const setZoomMethod = function (zoomLevel) { - const selectedElements = elemContext_.getSelectedElements(); - const res = elemContext_.getCanvas().getResolution(); - elemContext_.getSVGContent().setAttribute('viewBox', '0 0 ' + res.w / zoomLevel + ' ' + res.h / zoomLevel); - elemContext_.setCurrentZoom(zoomLevel); - selectedElements.forEach(function(elem){ - if (!elem) { return; } - elemContext_.getCanvas().selectorManager.requestSelector(elem).resize(); - }); - elemContext_.getCanvas().pathActions.zoomChange(); - elemContext_.getCanvas().runExtensions('zoomChanged', zoomLevel); -}; +export const setZoomMethod = (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((elem) => { + if (!elem) { return } + svgCanvas.selectorManager.requestSelector(elem).resize() + }) + svgCanvas.pathActions.zoomChange() + svgCanvas.runExtensions('zoomChanged', zoomLevel) +} /** * Change the current stroke/fill color/gradient value. @@ -321,45 +321,45 @@ export const setZoomMethod = function (zoomLevel) { * @fires module:elem-get-set.SvgCanvas#event:changed * @returns {void} */ -export const setColorMethod = function (type, val, preventUndo) { - const selectedElements = elemContext_.getSelectedElements(); - elemContext_.setCurShape(type, val); - elemContext_.setCurProperties(type + '_paint', { type: 'solidColor' }); - const elems = []; +export const setColorMethod = (type, val, preventUndo) => { + const selectedElements = svgCanvas.getSelectedElements() + svgCanvas.setCurShape(type, val) + svgCanvas.setCurProperties(type + '_paint', { type: 'solidColor' }) + const elems = [] /** * * @param {Element} e * @returns {void} */ - function addNonG(e) { + const 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) { - elemContext_.getCanvas().changeSelectedAttribute(type, val, elems); - elemContext_.call('changed', elems); + svgCanvas.changeSelectedAttribute(type, val, elems) + svgCanvas.call('changed', elems) } else { - elemContext_.changeSelectedAttributeNoUndoMethod(type, val, elems); + svgCanvas.changeSelectedAttributeNoUndo(type, val, elems) } } -}; +} /** * Apply the current gradient to selected element's fill or stroke. @@ -367,26 +367,26 @@ export const setColorMethod = function (type, val, preventUndo) { * @param {"fill"|"stroke"} type - String indicating "fill" or "stroke" to apply to an element * @returns {void} */ -export const setGradientMethod = function (type) { - if (!elemContext_.getCurProperties(type + '_paint') || - elemContext_.getCurProperties(type + '_paint').type === 'solidColor') { return; } - const canvas = elemContext_.getCanvas(); - let grad = canvas[type + 'Grad']; +export const setGradientMethod = (type) => { + if (!svgCanvas.getCurProperties(type + '_paint') || + 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 = elemContext_.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 = elemContext_.getCanvas().getNextId(); + grad.id = svgCanvas.getNextId() } else { // use existing gradient - grad = duplicateGrad; + grad = duplicateGrad } - elemContext_.getCanvas().setColor(type, 'url(#' + grad.id + ')'); -}; + svgCanvas.setColor(type, 'url(#' + grad.id + ')') +} /** * Check if exact gradient already exists. @@ -394,20 +394,20 @@ export const setGradientMethod = function (type) { * @param {SVGGradientElement} grad - The gradient DOM element to compare to others * @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' ]; +export const findDuplicateGradient = (grad) => { + 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; - radAttrs.forEach(function (attr) { - if (gradAttrs[attr] !== ogAttrs[attr]) { diff = true; } - }); + let diff = false + radAttrs.forEach((attr) => { + 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. @@ -468,24 +468,24 @@ export const findDuplicateGradient = function (grad) { * @param {module:jGraduate.jGraduatePaintOptions} paint - The jGraduate paint object to apply * @returns {void} */ -export const setPaintMethod = function (type, paint) { +export const setPaintMethod = (type, paint) => { // make a copy - const p = new jGraduate.Paint(paint); - this.setPaintOpacity(type, p.alpha / 100, true); + const p = new jGraduate.Paint(paint) + svgCanvas.setPaintOpacity(type, p.alpha / 100, true) // now set the current paint object - elemContext_.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': - elemContext_.setCanvas(type + 'Grad', p[p.type]); - elemContext_.getCanvas().setGradient(type); - break; + case 'solidColor': + svgCanvas.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. @@ -494,41 +494,41 @@ export const setPaintMethod = function (type, paint) { * @fires module:elem-get-set.SvgCanvas#event:changed * @returns {void} */ -export const setStrokeWidthMethod = function (val) { - const selectedElements = elemContext_.getSelectedElements(); - if (val === 0 && [ 'line', 'path' ].includes(elemContext_.getCanvas().getMode())) { - elemContext_.getCanvas().setStrokeWidth(1); - return; +export const setStrokeWidthMethod = (val) => { + const selectedElements = svgCanvas.getSelectedElements() + if (val === 0 && ['line', 'path'].includes(svgCanvas.getMode())) { + svgCanvas.setStrokeWidth(1) + return } - elemContext_.setCurProperties('stroke_width', val); + svgCanvas.setCurProperties('stroke_width', val) - const elems = []; + const elems = [] /** * * @param {Element} e * @returns {void} */ - function addNonG(e) { + const 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) { - elemContext_.getCanvas().changeSelectedAttribute('stroke-width', val, elems); - elemContext_.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. @@ -538,42 +538,42 @@ export const setStrokeWidthMethod = function (val) { * @fires module:elem-get-set.SvgCanvas#event:changed * @returns {void} */ -export const setStrokeAttrMethod = function (attr, val) { - const selectedElements = elemContext_.getSelectedElements(); - elemContext_.setCurShape(attr.replace('-', '_'), val); - const elems = []; +export const setStrokeAttrMethod = (attr, val) => { + 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, (e) => { if (e.nodeName !== 'g') { elems.push(e) } }) } else { - elems.push(elem); + elems.push(elem) } } } if (elems.length > 0) { - elemContext_.getCanvas().changeSelectedAttribute(attr, val, elems); - elemContext_.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 = elemContext_.getSelectedElements(); +export const getBoldMethod = () => { + const selectedElements = svgCanvas.getSelectedElements() // should only have one element selected - const selected = selectedElements[0]; - if (!isNullish(selected) && selected.tagName === 'text' && - isNullish(selectedElements[1])) { - return (selected.getAttribute('font-weight') === 'bold'); + const selected = selectedElements[0] + if (selected?.tagName === 'text' && + !selectedElements[1]) { + return (selected.getAttribute('font-weight') === 'bold') } - return false; -}; + return false +} /** * Make the selected element bold or normal. @@ -581,32 +581,81 @@ export const getBoldMethod = function () { * @param {boolean} b - Indicates bold (`true`) or normal (`false`) * @returns {void} */ -export const setBoldMethod = function (b) { - const selectedElements = elemContext_.getSelectedElements(); - const selected = selectedElements[0]; - if (!isNullish(selected) && selected.tagName === 'text' && - isNullish(selectedElements[1])) { - elemContext_.getCanvas().changeSelectedAttribute('font-weight', b ? 'bold' : 'normal'); +export const setBoldMethod = (b) => { + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] + if (selected?.tagName === 'text' && + !selectedElements[1]) { + svgCanvas.changeSelectedAttribute('font-weight', b ? 'bold' : 'normal') } if (!selectedElements[0].textContent) { - elemContext_.getCanvas().textActions.setCursor(); + svgCanvas.textActions.setCursor() } -}; +} + +/** + * Check whether selected element has the given text decoration value or not. + * @returns {boolean} Indicates whether or not element has the text decoration value + */ +export const hasTextDecorationMethod = (value) => { + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] + + if (selected?.tagName === 'text' && !selectedElements[1]) { + const attribute = selected.getAttribute('text-decoration') || '' + return attribute.includes(value) + } + + return false +} + +/** + * Adds the given text decoration value + * @param value The text decoration value + * @returns {void} + */ +export const addTextDecorationMethod = (value) => { + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] + if (selected?.tagName === 'text' && !selectedElements[1]) { + const oldValue = selected.getAttribute('text-decoration') || '' + svgCanvas.changeSelectedAttribute('text-decoration', (oldValue + ' ' + value).trim()) + } + if (selectedElements.length > 0 && !selectedElements[0].textContent) { + svgCanvas.textActions.setCursor() + } +} + +/** + * Removes the given text decoration value + * @param value The text decoration value + * @returns {void} + */ +export const removeTextDecorationMethod = (value) => { + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] + if (selected?.tagName === 'text' && !selectedElements[1]) { + const actualValues = selected.getAttribute('text-decoration') || '' + svgCanvas.changeSelectedAttribute('text-decoration', actualValues.replace(value, '').trim()) + } + if (selectedElements.length > 0 && !selectedElements[0].textContent) { + svgCanvas.textActions.setCursor() + } +} /** * Check whether selected element is in italics or not. * @function module:svgcanvas.SvgCanvas#getItalic * @returns {boolean} Indicates whether or not element is italic */ -export const getItalicMethod = function () { - const selectedElements = elemContext_.getSelectedElements(); - const selected = selectedElements[0]; - if (!isNullish(selected) && selected.tagName === 'text' && - isNullish(selectedElements[1])) { - return (selected.getAttribute('font-style') === 'italic'); +export const getItalicMethod = () => { + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] + if (selected?.tagName === 'text' && !selectedElements[1]) { + return (selected.getAttribute('font-style') === 'italic') } - return false; -}; + return false +} /** * Make the selected element italic or normal. @@ -614,42 +663,40 @@ export const getItalicMethod = function () { * @param {boolean} i - Indicates italic (`true`) or normal (`false`) * @returns {void} */ -export const setItalicMethod = function (i) { - const selectedElements = elemContext_.getSelectedElements(); - const selected = selectedElements[0]; - if (!isNullish(selected) && selected.tagName === 'text' && - isNullish(selectedElements[1])) { - elemContext_.getCanvas().changeSelectedAttribute('font-style', i ? 'italic' : 'normal'); +export const setItalicMethod = (i) => { + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] + if (selected?.tagName === 'text' && !selectedElements[1]) { + svgCanvas.changeSelectedAttribute('font-style', i ? 'italic' : 'normal') } if (!selectedElements[0].textContent) { - elemContext_.getCanvas().textActions.setCursor(); + svgCanvas.textActions.setCursor() } -}; +} /** * @function module:svgcanvas.SvgCanvas#setTextAnchorMethod Set the new text anchor * @param {string} value - The text anchor value (start, middle or end) * @returns {void} */ -export const setTextAnchorMethod = function (value) { - const selectedElements = elemContext_.getSelectedElements(); - const selected = selectedElements[0]; - if (!isNullish(selected) && selected.tagName === 'text' && - isNullish(selectedElements[1])) { - elemContext_.getCanvas().changeSelectedAttribute('text-anchor', value); +export const setTextAnchorMethod = (value) => { + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] + if (selected?.tagName === 'text' && !selectedElements[1]) { + svgCanvas.changeSelectedAttribute('text-anchor', value) } - if (!selectedElements[0].textContent) { - elemContext_.getCanvas().textActions.setCursor(); + if (selectedElements.length > 0 && !selectedElements[0].textContent) { + svgCanvas.textActions.setCursor() } -}; +} /** * @function module:svgcanvas.SvgCanvas#getFontFamily * @returns {string} The current font family */ -export const getFontFamilyMethod = function () { - return elemContext_.getCurText('font_family'); -}; +export const getFontFamilyMethod = () => { + return svgCanvas.getCurText('font_family') +} /** * Set the new font family. @@ -657,14 +704,14 @@ export const getFontFamilyMethod = function () { * @param {string} val - String with the new font family * @returns {void} */ -export const setFontFamilyMethod = function (val) { - const selectedElements = elemContext_.getSelectedElements(); - elemContext_.setCurText('font_family', val); - elemContext_.getCanvas().changeSelectedAttribute('font-family', val); - if (selectedElements[0] && !selectedElements[0].textContent) { - elemContext_.getCanvas().textActions.setCursor(); +export const setFontFamilyMethod = (val) => { + const selectedElements = svgCanvas.getSelectedElements() + svgCanvas.setCurText('font_family', val) + svgCanvas.changeSelectedAttribute('font-family', val) + if (!selectedElements[0]?.textContent) { + svgCanvas.textActions.setCursor() } -}; +} /** * Set the new font color. @@ -672,26 +719,26 @@ export const setFontFamilyMethod = function (val) { * @param {string} val - String with the new font color * @returns {void} */ -export const setFontColorMethod = function (val) { - elemContext_.setCurText('fill', val); - elemContext_.getCanvas().changeSelectedAttribute('fill', val); -}; +export const setFontColorMethod = (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 elemContext_.getCurText('fill'); -}; +export const getFontColorMethod = () => { + return svgCanvas.getCurText('fill') +} /** * @function module:svgcanvas.SvgCanvas#getFontSize * @returns {Float} The current font size */ -export const getFontSizeMethod = function () { - return elemContext_.getCurText('font_size'); -}; +export const getFontSizeMethod = () => { + return svgCanvas.getCurText('font_size') +} /** * Applies the given font size to the selected element. @@ -699,25 +746,24 @@ export const getFontSizeMethod = function () { * @param {Float} val - Float with the new font size * @returns {void} */ -export const setFontSizeMethod = function (val) { - const selectedElements = elemContext_.getSelectedElements(); - elemContext_.setCurText('font_size', val); - elemContext_.getCanvas().changeSelectedAttribute('font-size', val); - if (!selectedElements[0].textContent) { - elemContext_.getCanvas().textActions.setCursor(); +export const setFontSizeMethod = (val) => { + const selectedElements = svgCanvas.getSelectedElements() + svgCanvas.setCurText('font_size', val) + svgCanvas.changeSelectedAttribute('font-size', val) + if (!selectedElements[0]?.textContent) { + svgCanvas.textActions.setCursor() } -}; +} /** * @function module:svgcanvas.SvgCanvas#getText * @returns {string} The current text (`textContent`) of the selected element */ -export const getTextMethod = function () { - const selectedElements = elemContext_.getSelectedElements(); - const selected = selectedElements[0]; - if (isNullish(selected)) { return ''; } - return (selected) ? selected.textContent : ''; -}; +export const getTextMethod = () => { + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] + return (selected) ? selected.textContent : '' +} /** * Updates the text element with the given string. @@ -725,11 +771,11 @@ export const getTextMethod = function () { * @param {string} val - String with the new text * @returns {void} */ -export const setTextContentMethod = function (val) { - elemContext_.getCanvas().changeSelectedAttribute('#text', val); - elemContext_.getCanvas().textActions.init(val); - elemContext_.getCanvas().textActions.setCursor(); -}; +export const setTextContentMethod = (val) => { + 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 @@ -739,47 +785,48 @@ export const setTextContentMethod = function (val) { * @fires module:svgcanvas.SvgCanvas#event:changed * @returns {void} */ -export const setImageURLMethod = function (val) { - const selectedElements = elemContext_.getSelectedElements(); - const elem = selectedElements[0]; - if (!elem) { return; } +export const setImageURLMethod = (val) => { + 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) - elemContext_.getCanvas().selectorManager.requestSelector(elem).resize(); + svgCanvas.selectorManager.requestSelector(elem).resize() - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - elemContext_.addCommandToHistory(batchCmd); - elemContext_.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. @@ -787,33 +834,34 @@ export const setImageURLMethod = function (val) { * @param {string} val - String with the link URL/path * @returns {void} */ -export const setLinkURLMethod = function (val) { - const selectedElements = elemContext_.getSelectedElements(); - let elem = selectedElements[0]; - if (!elem) { return; } +export const setLinkURLMethod = (val) => { + 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 - })); + })) - elemContext_.addCommandToHistory(batchCmd); -}; + svgCanvas.addCommandToHistory(batchCmd) +} /** * Sets the `rx` and `ry` values to the selected `rect` element @@ -823,19 +871,20 @@ export const setLinkURLMethod = function (val) { * @fires module:svgcanvas.SvgCanvas#event:changed * @returns {void} */ -export const setRectRadiusMethod = function (val) { - const selectedElements = elemContext_.getSelectedElements(); - const selected = selectedElements[0]; - if (!isNullish(selected) && selected.tagName === 'rect') { - const r = Number(selected.getAttribute('rx')); +export const setRectRadiusMethod = (val) => { + const { ChangeElementCommand } = svgCanvas.history + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] + if (selected?.tagName === 'rect') { + const r = Number(selected.getAttribute('rx')) if (r !== val) { - selected.setAttribute('rx', val); - selected.setAttribute('ry', val); - elemContext_.addCommandToHistory(new ChangeElementCommand(selected, { rx: r, ry: r }, 'Radius')); - elemContext_.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. @@ -843,20 +892,17 @@ export const setRectRadiusMethod = function (val) { * @param {string} url * @returns {void} */ -export const makeHyperlinkMethod = function (url) { - elemContext_.getCanvas().groupSelectedElements('a', url); - - // TODO: If element is a single "g", convert to "a" - // if (selectedElements.length > 1 && selectedElements[1]) { -}; +export const makeHyperlinkMethod = (url) => { + svgCanvas.groupSelectedElements('a', url) +} /** * @function module:svgcanvas.SvgCanvas#removeHyperlink * @returns {void} */ -export const removeHyperlinkMethod = function () { - elemContext_.getCanvas().ungroupSelectedElement(); -}; +export const removeHyperlinkMethod = () => { + svgCanvas.ungroupSelectedElement() +} /** * Group: Element manipulation. @@ -868,9 +914,9 @@ export const removeHyperlinkMethod = function () { * @param {Integer} newType - New segment type. See {@link https://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg} for list * @returns {void} */ -export const setSegTypeMethod = function (newType) { - elemContext_.getCanvas().pathActions.setSegType(newType); -}; +export const setSegTypeMethod = (newType) => { + svgCanvas.pathActions.setSegType(newType) +} /** * Set the background of the editor (NOT the actual document). @@ -879,49 +925,49 @@ export const setSegTypeMethod = function (newType) { * @param {string} url - URL or path to image to use * @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); +export const setBackgroundMethod = (color, url) => { + const bg = getElement('canvasBackground') + const border = bg.querySelector('rect') + let bgImg = getElement('background_image') + let bgPattern = getElement('background_pattern') + border.setAttribute('fill', color === 'chessboard' ? '#fff' : color) if (color === 'chessboard') { if (!bgPattern) { - bgPattern = elemContext_.getDOMDocument().createElementNS(NS.SVG, 'foreignObject'); - elemContext_.getCanvas().assignAttributes(bgPattern, { + 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'); - elemContext_.getCanvas().assignAttributes(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 = elemContext_.getDOMDocument().createElementNS(NS.SVG, 'image'); - elemContext_.getCanvas().assignAttributes(bgImg, { + 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 7b343f43..97ef3642 100644 --- a/src/svgcanvas/event.js +++ b/src/svgcanvas/event.js @@ -5,71 +5,95 @@ * @copyright 2011 Jeff Schiller */ import { - assignAttributes, cleanupElement, getElem, getRotationAngle, snapToGrid, walkTree, - getBBox as utilsGetBBox, isNullish, preventClickDefault, setHref -} from './utilities.js'; + assignAttributes, cleanupElement, getElement, getRotationAngle, snapToGrid, walkTree, + preventClickDefault, setHref, getBBox +} from './utilities.js' import { convertAttrs -} from '../common/units.js'; +} from '../common/units.js' import { transformPoint, hasMatrixTransform, getMatrix, snapToAngle -} from './math.js'; -import { supportsNonScalingStroke } from '../common/browser.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 eventContext_ = null; +let svgCanvas = null /** * @function module:undo.init * @param {module:undo.eventContext} eventContext * @returns {void} */ -export const init = function (eventContext) { - eventContext_ = eventContext; -}; +export const init = (canvas) => { + svgCanvas = canvas + svgCanvas.mouseDownEvent = mouseDownEvent + svgCanvas.mouseMoveEvent = mouseMoveEvent + svgCanvas.dblClickEvent = dblClickEvent + svgCanvas.mouseUpEvent = mouseUpEvent + svgCanvas.mouseOutEvent = mouseOutEvent + svgCanvas.DOMMouseScrollEvent = DOMMouseScrollEvent +} -export const getBsplinePoint = function (t) { - const spline = { x: 0, y: 0 }; - const p0 = { x: eventContext_.getControllPoint2('x'), y: eventContext_.getControllPoint2('y') }; - const p1 = { x: eventContext_.getControllPoint1('x'), y: eventContext_.getControllPoint1('y') }; - const p2 = { x: eventContext_.getStart('x'), y: eventContext_.getStart('y') }; - const p3 = { x: eventContext_.getEnd('x'), y: eventContext_.getEnd('y') }; - const S = 1.0 / 6.0; - const t2 = t * t; - const t3 = t2 * t; +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 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 - }; -}; + } +} + +// update the dummy transform in our transform list +// to be a translate. We need to check if there was a transformation +// to avoid loosing it +const updateTransformList = (svgRoot, element, dx, dy) => { + const xform = svgRoot.createSVGTransform() + xform.setTranslate(dx, dy) + const tlist = element.transform?.baseVal + if (tlist.numberOfItems) { + const firstItem = tlist.getItem(0) + if (firstItem.type === 2) { // SVG_TRANSFORM_TRANSLATE = 2 + tlist.replaceItem(xform, 0) + } else { + tlist.insertItemBefore(xform, 0) + } + } else { + tlist.appendItem(xform) + } +} /** * @@ -78,465 +102,444 @@ export const getBsplinePoint = function (t) { * @fires module:svgcanvas.SvgCanvas#event:ext_mouseMove * @returns {void} */ -export const mouseMoveEvent = function (evt) { - const selectedElements = eventContext_.getSelectedElements; - const currentZoom = eventContext_.getCurrentZoom(); - const svgRoot = eventContext_.getSVGRoot(); - const svgCanvas = eventContext_.getCanvas(); +const mouseMoveEvent = (evt) => { + // if the mouse is move without dragging an element, just return. + if (!svgCanvas.getStarted()) { return } + if (evt.button === 1 || svgCanvas.spaceKey) { return } - if (!eventContext_.getStarted()) { return; } - if (evt.button === 1 || svgCanvas.spaceKey) { return; } + evt.preventDefault() - 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, eventContext_.getrootSctm()); - const mouseX = pt.x * currentZoom; - const mouseY = pt.y * currentZoom; - const shape = getElem(eventContext_.getId()); + const selectedElements = svgCanvas.getSelectedElements() + const zoom = svgCanvas.getZoom() + const svgRoot = svgCanvas.getSvgRoot() + const selected = selectedElements[0] - let realX = mouseX / currentZoom; - let x = realX; - let realY = mouseY / currentZoom; - let y = realY; + let i + let xya + let cx + let cy + let dx + let dy + let len + let angle + let box - if (eventContext_.getCurConfig().gridSnapping) { - x = snapToGrid(x); - y = snapToGrid(y); + const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()) + const mouseX = pt.x * zoom + const mouseY = pt.y * zoom + const shape = getElement(svgCanvas.getId()) + + let realX = mouseX / zoom + let x = realX + let realY = mouseY / zoom + let y = realY + + if (svgCanvas.getCurConfig().gridSnapping) { + x = snapToGrid(x) + y = snapToGrid(y) } - evt.preventDefault(); - let tlist; - switch (eventContext_.getCurrentMode()) { - 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 - eventContext_.getStartX(); - dy = y - eventContext_.getStartY(); - if (eventContext_.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; } - // if (i === 0) { - // const box = utilsGetBBox(selected); - // selectedBBoxes[i].x = box.x + dx; - // selectedBBoxes[i].y = box.y + dy; - // } - - // update the dummy transform in our transform list - // to be a translate - const xform = svgRoot.createSVGTransform(); - tlist = 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(); + let tlist + switch (svgCanvas.getCurrentMode()) { + 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 (selected) { + dx = x - svgCanvas.getStartX() + dy = y - svgCanvas.getStartY() + if (svgCanvas.getCurConfig().gridSnapping) { + dx = snapToGrid(dx) + dy = snapToGrid(dy) } - svgCanvas.call('transition', selectedElements()); - } - } - break; - } case 'multiselect': { - realX *= currentZoom; - realY *= currentZoom; - assignAttributes(eventContext_.getRubberBox(), { - x: Math.min(eventContext_.getRStartX(), realX), - y: Math.min(eventContext_.getRStartY(), realY), - width: Math.abs(realX - eventContext_.getRStartX()), - height: Math.abs(realY - eventContext_.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 = eventContext_.getIntersectionList(); - - // For every element in the intersection, add if not present in selectedElements. - len = newList.length; - for (i = 0; i < len; ++i) { - const intElem = newList[i]; - // Found an element that was not selected before, so we should add it. - if (!selectedElements().includes(intElem)) { - elemsToAdd.push(intElem); - } - // Found an element that was already selected, so we shouldn't remove it. - const foundInd = elemsToRemove.indexOf(intElem); - if (foundInd !== -1) { - elemsToRemove.splice(foundInd, 1); - } - } - - if (elemsToRemove.length > 0) { - svgCanvas.removeFromSelection(elemsToRemove); - } - - if (elemsToAdd.length > 0) { - svgCanvas.addToSelection(elemsToAdd); - } - - break; - } case 'resize': { - // we track the resize bounding box and translate/scale the selected element - // while the mouse is down, when mouse goes up, we use this to recalculate - // the shape's coordinates - tlist = selected.transform.baseVal; - const hasMatrix = hasMatrixTransform(tlist); - box = hasMatrix ? eventContext_.getInitBbox() : utilsGetBBox(selected); - let left = box.x; - let top = box.y; - let { width, height } = box; - dx = (x - eventContext_.getStartX()); - dy = (y - eventContext_.getStartY()); - - if (eventContext_.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 (!eventContext_.getCurrentResizeMode().includes('n') && !eventContext_.getCurrentResizeMode().includes('s')) { - dy = 0; - } - if (!eventContext_.getCurrentResizeMode().includes('e') && !eventContext_.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 (eventContext_.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 (eventContext_.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 (eventContext_.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 *= currentZoom; - realY *= currentZoom; - assignAttributes(eventContext_.getRubberBox(), { - x: Math.min(eventContext_.getRStartX() * currentZoom, realX), - y: Math.min(eventContext_.getRStartY() * currentZoom, realY), - width: Math.abs(realX - eventContext_.getRStartX() * currentZoom), - height: Math.abs(realY - eventContext_.getRStartY() * currentZoom) - }, 100); - break; - } case 'text': { - assignAttributes(shape, { - x, - y - }, 1000); - break; - } case 'line': { - if (eventContext_.getCurConfig().gridSnapping) { - x = snapToGrid(x); - y = snapToGrid(y); - } - - let x2 = x; - let y2 = y; - - if (evt.shiftKey) { - xya = snapToAngle(eventContext_.getStartX(), eventContext_.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 = (eventContext_.getCurrentMode() === 'square') || evt.shiftKey; - let - w = Math.abs(x - eventContext_.getStartX()); - let h = Math.abs(y - eventContext_.getStartY()); - let newX; let newY; - if (square) { - w = h = Math.max(w, h); - newX = eventContext_.getStartX() < x ? eventContext_.getStartX() : eventContext_.getStartX() - w; - newY = eventContext_.getStartY() < y ? eventContext_.getStartY() : eventContext_.getStartY() - h; - } else { - newX = Math.min(eventContext_.getStartX(), x); - newY = Math.min(eventContext_.getStartY(), y); - } - - if (eventContext_.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 (eventContext_.getCurConfig().gridSnapping) { - rad = snapToGrid(rad); - } - shape.setAttribute('r', rad); - break; - } case 'ellipse': { - cx = Number(shape.getAttribute('cx')); - cy = Number(shape.getAttribute('cy')); - if (eventContext_.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': { - eventContext_.setFreehand('minx', Math.min(realX, eventContext_.getFreehand('minx'))); - eventContext_.setFreehand('maxx', Math.max(realX, eventContext_.getFreehand('maxx'))); - eventContext_.setFreehand('miny', Math.min(realY, eventContext_.getFreehand('miny'))); - eventContext_.setFreehand('maxy', Math.max(realY, eventContext_.getFreehand('maxy'))); - } - // Fallthrough - case 'fhpath': { - // dAttr += + realX + ',' + realY + ' '; - // shape.setAttribute('points', dAttr); - eventContext_.setEnd('x', realX); - eventContext_.setEnd('y', realY); - if (eventContext_.getControllPoint2('x') && eventContext_.getControllPoint2('y')) { - for (i = 0; i < eventContext_.getStepCount() - 1; i++) { - eventContext_.setParameter(i / eventContext_.getStepCount()); - eventContext_.setNextParameter((i + 1) / eventContext_.getStepCount()); - eventContext_.setbSpline(getBsplinePoint(eventContext_.getNextParameter())); - eventContext_.setNextPos({ x: eventContext_.getbSpline('x'), y: eventContext_.getbSpline('y') }); - eventContext_.setbSpline(getBsplinePoint(eventContext_.getParameter())); - eventContext_.setSumDistance( - eventContext_.getSumDistance() + Math.sqrt((eventContext_.getNextPos('x') - - eventContext_.getbSpline('x')) * (eventContext_.getNextPos('x') - - eventContext_.getbSpline('x')) + (eventContext_.getNextPos('y') - - eventContext_.getbSpline('y')) * (eventContext_.getNextPos('y') - eventContext_.getbSpline('y'))) - ); - if (eventContext_.getSumDistance() > eventContext_.getThreSholdDist()) { - eventContext_.setSumDistance(eventContext_.getSumDistance() - eventContext_.getThreSholdDist()); - - // Faster than completely re-writing the points attribute. - const point = eventContext_.getSVGContent().createSVGPoint(); - point.x = eventContext_.getbSpline('x'); - point.y = eventContext_.getbSpline('y'); - shape.points.appendItem(point); + if (dx || dy) { + selectedElements.forEach((el) => { + if (el) { + updateTransformList(svgRoot, el, dx, dy) + // update our internal bbox that we're tracking while dragging + svgCanvas.selectorManager.requestSelector(el).resize() + } + }) + svgCanvas.call('transition', selectedElements) } } + break } - eventContext_.setControllPoint2('x', eventContext_.getControllPoint1('x')); - eventContext_.setControllPoint2('y', eventContext_.getControllPoint1('y')); - eventContext_.setControllPoint1('x', eventContext_.getStart('x')); - eventContext_.setControllPoint1('y', eventContext_.getStart('y')); - eventContext_.setStart({ x: eventContext_.getEnd('x'), y: eventContext_.getEnd('y') }); - break; - // update path stretch line coordinates - } case 'path': - // fall through - case 'pathedit': { - x *= currentZoom; - y *= currentZoom; + 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) - if (eventContext_.getCurConfig().gridSnapping) { - x = snapToGrid(x); - y = snapToGrid(y); - eventContext_.setStartX(snapToGrid(eventContext_.getStartX())); - eventContext_.setStartY(snapToGrid(eventContext_.getStartY())); + // 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) + } + // 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 (elemsToAdd.length > 0) { + svgCanvas.addToSelection(elemsToAdd) + } + + break } - if (evt.shiftKey) { - const { path } = pathModule; - let x1; let y1; - if (path) { - x1 = path.dragging ? path.dragging[0] : eventContext_.getStartX(); - y1 = path.dragging ? path.dragging[1] : eventContext_.getStartY(); + 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()) + + 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 { - x1 = eventContext_.getStartX(); - y1 = eventContext_.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); + + svgCanvas.selectorManager.requestSelector(selected).resize() + svgCanvas.call('transition', selectedElements) + + break } - - if (eventContext_.getRubberBox() && eventContext_.getRubberBox().getAttribute('display') !== 'none') { - realX *= currentZoom; - realY *= currentZoom; - assignAttributes(eventContext_.getRubberBox(), { - x: Math.min(eventContext_.getRStartX() * currentZoom, realX), - y: Math.min(eventContext_.getRStartY() * currentZoom, realY), - width: Math.abs(realX - eventContext_.getRStartX() * currentZoom), - height: Math.abs(realY - eventContext_.getRStartY() * currentZoom) - }, 100); + 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 } - svgCanvas.pathActions.mouseMove(x, y); - - break; - } case 'textedit': { - x *= currentZoom; - y *= currentZoom; - // if (eventContext_.getRubberBox() && eventContext_.getRubberBox().getAttribute('display') !== 'none') { - // assignAttributes(eventContext_.getRubberBox(), { - // x: Math.min(eventContext_.getStartX(), x), - // y: Math.min(eventContext_.getStartY(), y), - // width: Math.abs(x - eventContext_.getStartX()), - // height: Math.abs(y - eventContext_.getStartY()) - // }, 100); - // } - - svgCanvas.textActions.mouseMove(mouseX, mouseY); - - break; - } case 'rotate': { - box = utilsGetBBox(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 (eventContext_.getCurConfig().gridSnapping) { - angle = snapToGrid(angle); - } - if (evt.shiftKey) { // restrict rotations to nice angles (WRS) - const snap = 45; - angle = Math.round(angle / snap) * snap; + case 'text': { + assignAttributes(shape, { + x, + y + }, 1000) + break } + case 'line': { + if (svgCanvas.getCurConfig().gridSnapping) { + x = snapToGrid(x) + y = snapToGrid(y) + } - svgCanvas.setRotationAngle(angle < -180 ? (360 + angle) : angle, true); - svgCanvas.call('transition', selectedElements()); - break; - } default: - break; + 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': + case 'rect': + 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) + } + } + } + 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()?.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 + 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: + // A mode can be defined by an extenstion + break } /** -* The mouse has moved on the canvas area. -* @event module:svgcanvas.SvgCanvas#event:ext_mouseMove -* @type {PlainObject} -* @property {MouseEvent} event The event object -* @property {Float} mouse_x x coordinate on canvas -* @property {Float} mouse_y y coordinate on canvas -* @property {Element} selected Refers to the first selected element -*/ + * The mouse has moved on the canvas area. + * @event module:svgcanvas.SvgCanvas#event:ext_mouseMove + * @type {PlainObject} + * @property {MouseEvent} event The event object + * @property {Float} mouse_x x coordinate on canvas + * @property {Float} mouse_y y coordinate on canvas + * @property {Element} selected Refers to the first selected element + */ svgCanvas.runExtensions('mouseMove', /** @type {module:svgcanvas.SvgCanvas#event:ext_mouseMove} */ { event: evt, mouse_x: mouseX, mouse_y: mouseY, selected - }); -}; // mouseMove() + }) +} // mouseMove() /** * * @returns {void} */ -export const mouseOutEvent = function () { - const svgCanvas = eventContext_.getCanvas(); - const { $id } = svgCanvas; - if(eventContext_.getCurrentMode() !== 'select' && eventContext_.getStarted()) { - const event = new Event("mouseup"); - $id('svgcanvas').dispatchEvent(event); +const mouseOutEvent = () => { + 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 @@ -551,244 +554,234 @@ export const mouseOutEvent = function () { * @fires module:svgcanvas.SvgCanvas#event:ext_mouseUp * @returns {void} */ -export const mouseUpEvent = function (evt) { - const selectedElements = eventContext_.getSelectedElements(); - const currentZoom = eventContext_.getCurrentZoom(); - const svgCanvas = eventContext_.getCanvas(); - if (evt.button === 2) { return; } - const tempJustSelected = eventContext_.getJustSelected(); - eventContext_.setJustSelected(null); - if (!eventContext_.getStarted()) { return; } - const pt = transformPoint(evt.clientX, evt.clientY, eventContext_.getrootSctm()); - const mouseX = pt.x * currentZoom; - const mouseY = pt.y * currentZoom; - const x = mouseX / currentZoom; - const y = mouseY / currentZoom; +const mouseUpEvent = (evt) => { + if (evt.button === 2) { return } + if (!svgCanvas.getStarted()) { return } - let element = getElem(eventContext_.getId()); - let keep = false; + const selectedElements = svgCanvas.getSelectedElements() + const zoom = svgCanvas.getZoom() - const realX = x; - const realY = y; + const tempJustSelected = svgCanvas.getJustSelected() + svgCanvas.setJustSelected(null) + + 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 = getElement(svgCanvas.getId()) + let keep = false + + const realX = x + const realY = y // TODO: Make true when in multi-unit mode - const useUnit = false; // (eventContext_.getCurConfig().baseUnit !== 'px'); - eventContext_.setStarted(false); - let t; - switch (eventContext_.getCurrentMode()) { - // intentionally fall-through to select here - case 'resize': - case 'multiselect': - if (!isNullish(eventContext_.getRubberBox())) { - eventContext_.getRubberBox().setAttribute('display', 'none'); - eventContext_.setCurBBoxes([]); - } - eventContext_.setCurrentMode('select'); + 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 (!isNullish(selectedElements[0])) { - // if we only have one selected element - if (isNullish(selectedElements[1])) { - // set our current stroke/fill properties to the element's - const selected = selectedElements[0]; - switch (selected.tagName) { - case 'g': - case 'use': - case 'image': - case 'foreignObject': - break; - default: - eventContext_.setCurProperties('fill', selected.getAttribute('fill')); - eventContext_.setCurProperties('fill_opacity', selected.getAttribute('fill-opacity')); - eventContext_.setCurProperties('stroke', selected.getAttribute('stroke')); - eventContext_.setCurProperties('stroke_opacity', selected.getAttribute('stroke-opacity')); - eventContext_.setCurProperties('stroke_width', selected.getAttribute('stroke-width')); - eventContext_.setCurProperties('stroke_dasharray', selected.getAttribute('stroke-dasharray')); - eventContext_.setCurProperties('stroke_linejoin', selected.getAttribute('stroke-linejoin')); - eventContext_.setCurProperties('stroke_linecap', selected.getAttribute('stroke-linecap')); - } - - if (selected.tagName === 'text') { - eventContext_.setCurText('font_size', selected.getAttribute('font-size')); - eventContext_.setCurText('font_family', selected.getAttribute('font-family')); - } - svgCanvas.selectorManager.requestSelector(selected).showGrips(true); - - // This shouldn't be necessary as it was done on mouseDown... - // svgCanvas.call('selected', [selected]); - } - // always recalculate dimensions to strip off stray identity transforms - svgCanvas.recalculateAllSelectedDimensions(); - // if it was being dragged/resized - if (realX !== eventContext_.getRStartX() || realY !== eventContext_.getRStartY()) { - const len = selectedElements.length; - for (let i = 0; i < len; ++i) { - if (isNullish(selectedElements[i])) { break; } - if (!selectedElements[i].firstChild) { - // Not needed for groups (incorrectly resizes elems), possibly not needed at all? - svgCanvas.selectorManager.requestSelector(selectedElements[i]).resize(); + 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 + case 'text': + svgCanvas.setCurText('font_size', selected.getAttribute('font-size')) + svgCanvas.setCurText('font_family', selected.getAttribute('font-family')) + // fallthrough + 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')) } + svgCanvas.selectorManager.requestSelector(selected).showGrips(true) } - // 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]); - // 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 ]); - } - } // no change in mouse position + // 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 (!selectedElements[i]) { break } + } + // no change in position/size, so maybe we should move to pathedit + } else { + t = evt.target + if (selectedElements[0].nodeName === 'path' && !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]) + } + } // no change in mouse position - // Remove non-scaling stroke - if (supportsNonScalingStroke()) { - const elem = selectedElements[0]; + // Remove non-scaling stroke + const elem = selectedElements[0] if (elem) { - elem.removeAttribute('style'); - walkTree(elem, function (el) { - el.removeAttribute('style'); - }); + elem.removeAttribute('style') + walkTree(elem, (el) => { + el.removeAttribute('style') + }) } } + return + case 'zoom': { + 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) + } + 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) } - return; - case 'zoom': { - if (!isNullish(eventContext_.getRubberBox())) { - eventContext_.getRubberBox().setAttribute('display', 'none'); + 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' } - const factor = evt.shiftKey ? 0.5 : 2; - svgCanvas.call('zoomed', { - x: Math.min(eventContext_.getRStartX(), realX), - y: Math.min(eventContext_.getRStartY(), realY), - width: Math.abs(realX - eventContext_.getRStartX()), - height: Math.abs(realY - eventContext_.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 - eventContext_.setSumDistance(0); - eventContext_.setControllPoint2('x', 0); - eventContext_.setControllPoint2('y', 0); - eventContext_.setControllPoint1('x', 0); - eventContext_.setControllPoint1('y', 0); - eventContext_.setStart({ x: 0, y: 0 }); - eventContext_.setEnd('x', 0); - eventContext_.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 '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 '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) || eventContext_.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 ((eventContext_.getFreehand('maxx') - eventContext_.getFreehand('minx')) > 0 && - (eventContext_.getFreehand('maxy') - eventContext_.getFreehand('miny')) > 0) { - element = svgCanvas.addSVGElementFromJson({ - element: 'ellipse', - curStyles: true, - attr: { - cx: (eventContext_.getFreehand('minx') + eventContext_.getFreehand('maxx')) / 2, - cy: (eventContext_.getFreehand('miny') + eventContext_.getFreehand('maxy')) / 2, - rx: (eventContext_.getFreehand('maxx') - eventContext_.getFreehand('minx')) / 2, - ry: (eventContext_.getFreehand('maxy') - eventContext_.getFreehand('miny')) / 2, - id: eventContext_.getId() - } - }); - svgCanvas.call('changed', [ element ]); - keep = true; - } - break; - case 'fhrect': - if ((eventContext_.getFreehand('maxx') - eventContext_.getFreehand('minx')) > 0 && - (eventContext_.getFreehand('maxy') - eventContext_.getFreehand('miny')) > 0) { - element = svgCanvas.addSVGElementFromJson({ - element: 'rect', - curStyles: true, - attr: { - x: eventContext_.getFreehand('minx'), - y: eventContext_.getFreehand('miny'), - width: (eventContext_.getFreehand('maxx') - eventContext_.getFreehand('minx')), - height: (eventContext_.getFreehand('maxy') - eventContext_.getFreehand('miny')), - id: eventContext_.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 - eventContext_.setStarted(true); + break + case 'fhellipse': + if ((svgCanvas.getFreehand('maxx') - svgCanvas.getFreehand('minx')) > 0 && + (svgCanvas.getFreehand('maxy') - svgCanvas.getFreehand('miny')) > 0) { + element = svgCanvas.addSVGElementsFromJson({ + 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.addSVGElementsFromJson({ + 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) - 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; - eventContext_.setCurrentMode('select'); - const batchCmd = svgCanvas.undoMgr.finishUndoableChange(); - if (!batchCmd.isEmpty()) { - eventContext_.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; + 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 } /** @@ -803,121 +796,120 @@ export const mouseUpEvent = function (evt) { event: evt, mouse_x: mouseX, mouse_y: mouseY - }, true); + }, true) - extResult.forEach(function(r){ + extResult.forEach((r) => { if (r) { keep = r.keep || keep; - ({ element } = r); - eventContext_.setStarted(r.started || eventContext_.getStarted()); + ({ element } = r) + svgCanvas.setStarted(r.started || svgCanvas.getStarted()) } - }); + }) - if (!keep && !isNullish(element)) { - svgCanvas.getCurrentDrawing().releaseId(eventContext_.getId()); - element.remove(); - element = null; + if (!keep && element) { + 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 && t.parentNode && t.parentNode.parentNode && t.parentNode.parentNode.tagName === 'g') { - t = t.parentNode; + while (t?.parentNode?.parentNode?.tagName === 'g') { + t = t.parentNode } // if we are not in the middle of creating a path, and we've clicked on some shape, // then go to Select mode. // WebKit returns
when the canvas is clicked, Firefox/Opera return - if ((eventContext_.getCurrentMode() !== 'path' || !eventContext_.getDrawnPath()) && - t && t.parentNode && - t.parentNode.id !== 'selectorParentGroup' && + if ((svgCanvas.getCurrentMode() !== 'path' || !svgCanvas.getDrawnPath()) && + t && + t.parentNode?.id !== 'selectorParentGroup' && 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)) { + } else if (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 = eventContext_.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 (eventContext_.getCurrentMode() === 'path') { - svgCanvas.pathActions.toEditMode(element); - } else if (eventContext_.getCurConfig().selectNew) { - const modes = [ 'circle', 'ellipse', 'square', 'rect', 'fhpath', 'line', 'fhellipse', 'fhrect', 'star', 'polygon' ]; - if ( modes.indexOf(eventContext_.getCurrentMode()) !== -1) { - svgCanvas.setMode('select'); + setTimeout(() => { + 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) + } 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') } - 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() - eventContext_.addCommandToHistory(new InsertElementCommand(element)); - svgCanvas.call('changed', [ element ]); - }, aniDur * 1000); + svgCanvas.addCommandToHistory(new InsertElementCommand(element)) + svgCanvas.call('changed', [element]) + }, aniDur * 1000) } - eventContext_.setStartTransform(null); -}; + svgCanvas.setStartTransform(null) +} -export const dblClickEvent = function (evt) { - const selectedElements = eventContext_.getSelectedElements(); - const evtTarget = evt.target; - const parent = evtTarget.parentNode; - const svgCanvas = eventContext_.getCanvas(); +const dblClickEvent = (evt) => { + 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' && eventContext_.getCurrentMode() !== 'textedit') { - const pt = transformPoint(evt.clientX, evt.clientY, eventContext_.getrootSctm()); - svgCanvas.textActions.select(mouseTarget, pt.x, pt.y); + if (tagName === 'text' && svgCanvas.getCurrentMode() !== 'textedit') { + 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 === eventContext_.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 (eventContext_.getCurrentGroup()) { - draw.leaveContext(); + if (svgCanvas.getCurrentGroup()) { + draw.leaveContext() } if ((parent.tagName !== 'g' && parent.tagName !== 'a') || @@ -925,10 +917,10 @@ export const dblClickEvent = function (evt) { mouseTarget === svgCanvas.selectorManager.selectorParentGroup ) { // Escape from in-group edit - return; + return } - draw.setContext(mouseTarget); -}; + draw.setContext(mouseTarget) +} /** * Follows these conditions: @@ -940,339 +932,345 @@ export const dblClickEvent = function (evt) { * @fires module:svgcanvas.SvgCanvas#event:ext_mouseDown * @returns {void} */ -export const mouseDownEvent = function (evt) { - const dataStorage = eventContext_.getDataStorage(); - const selectedElements = eventContext_.getSelectedElements; - const currentZoom = eventContext_.getCurrentZoom(); - const svgCanvas = eventContext_.getCanvas(); - const curShape = svgCanvas.getStyle(); - const svgRoot = eventContext_.getSVGRoot(); - const { $id } = svgCanvas; +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 - 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) } - eventContext_.setRootSctm($id('svgcontent').querySelector('g').getScreenCTM().inverse()); + svgCanvas.setRootSctm($id('svgcontent').querySelector('g').getScreenCTM().inverse()) - const pt = transformPoint(evt.clientX, evt.clientY, eventContext_.getrootSctm()); - const mouseX = pt.x * currentZoom; - const mouseY = pt.y * currentZoom; + 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(eventContext_.getCurrentMode() === 'path'){ - return; + if (svgCanvas.getCurrentMode() === 'path') { + return } - eventContext_.setCurrentMode('select'); - eventContext_.setLastClickPoint(pt); + svgCanvas.setCurrentMode('select') + svgCanvas.setLastClickPoint(pt) } - let x = mouseX / currentZoom; - let y = mouseY / currentZoom; - 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; - eventContext_.setStartX(x); - eventContext_.setRStartX(x); - const realY = y; - eventContext_.setStartY(y); - eventContext_.setRStartY(y); + const realX = x + svgCanvas.setStartX(x) + svgCanvas.setRStartX(x) + const realY = y + svgCanvas.setStartY(y) + svgCanvas.setRStartY(y) - if (eventContext_.getCurConfig().gridSnapping) { - x = snapToGrid(x); - y = snapToGrid(y); - eventContext_.setStartX(snapToGrid(eventContext_.getStartX())); - eventContext_.setStartY(snapToGrid(eventContext_.getStartY())); + if (svgCanvas.getCurConfig().gridSnapping) { + 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'); + if (mouseTarget === svgCanvas.selectorManager.selectorParentGroup && selectedElements[0]) { + const grip = evt.target + const griptype = dataStorage.get(grip, 'type') // rotating if (griptype === 'rotate') { - eventContext_.setCurrentMode('rotate'); - // eventContext_.setCurrentRotateMode(dataStorage.get(grip, 'dir')); + svgCanvas.setCurrentMode('rotate') + // svgCanvas.setCurrentRotateMode(dataStorage.get(grip, 'dir')); // resizing } else if (griptype === 'resize') { - eventContext_.setCurrentMode('resize'); - eventContext_.setCurrentResizeMode(dataStorage.get(grip, 'dir')); + svgCanvas.setCurrentMode('resize') + svgCanvas.setCurrentResizeMode(dataStorage.get(grip, 'dir')) } - mouseTarget = selectedElements()[0]; + mouseTarget = selectedElements[0] } - eventContext_.setStartTransform(mouseTarget.getAttribute('transform')); + svgCanvas.setStartTransform(mouseTarget.getAttribute('transform')) - const tlist = mouseTarget.transform.baseVal; - switch (eventContext_.getCurrentMode()) { - case 'select': - eventContext_.setStarted(true); - eventContext_.setCurrentResizeMode('none'); - if (rightClick) { eventContext_.setStarted(false); } + const tlist = mouseTarget.transform.baseVal + // consolidate transforms using standard SVG but keep the transformation used for the move/scale + if (tlist.numberOfItems > 1) { + const firstTransform = tlist.getItem(0) + tlist.removeItem(0) + tlist.consolidate() + tlist.insertItemBefore(firstTransform, 0) + } + switch (svgCanvas.getCurrentMode()) { + case 'select': + svgCanvas.setStarted(true) + svgCanvas.setCurrentResizeMode('none') + if (rightClick) { svgCanvas.setStarted(false) } - if (mouseTarget !== svgRoot) { - // if this element is not yet selected, clear selection and select it - if (!selectedElements().includes(mouseTarget)) { - // only clear selection if shift is not pressed (otherwise, add - // element to selection) - if (!evt.shiftKey) { - // No need to do the call here as it will be done on addToSelection - svgCanvas.clearSelection(true); + if (mouseTarget !== svgRoot) { + // if this element is not yet selected, clear selection and select it + if (!selectedElements.includes(mouseTarget)) { + // only clear selection if shift is not pressed (otherwise, add + // element to selection) + if (!evt.shiftKey) { + // No need to do the call here as it will be done on addToSelection + svgCanvas.clearSelection(true) + } + svgCanvas.addToSelection([mouseTarget]) + svgCanvas.setJustSelected(mouseTarget) + svgCanvas.pathActions.clear() } - svgCanvas.addToSelection([ mouseTarget ]); - eventContext_.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) { - // 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()); + 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 (!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(); - eventContext_.setCurrentMode('multiselect'); - if (isNullish(eventContext_.getRubberBox())) { - eventContext_.setRubberBox(svgCanvas.selectorManager.getRubberBandBox()); - } - eventContext_.setRStartX(eventContext_.getRStartX() * currentZoom); - eventContext_.setRStartY(eventContext_.getRStartY() * currentZoom); + } else if (!rightClick) { + svgCanvas.clearSelection() + svgCanvas.setCurrentMode('multiselect') + if (!svgCanvas.getRubberBox()) { + svgCanvas.setRubberBox(svgCanvas.selectorManager.getRubberBandBox()) + } + svgCanvas.setRStartX(svgCanvas.getRStartX() * zoom) + svgCanvas.setRStartY(svgCanvas.getRStartY() * zoom) - assignAttributes(eventContext_.getRubberBox(), { - x: eventContext_.getRStartX(), - y: eventContext_.getRStartY(), + assignAttributes(svgCanvas.getRubberBox(), { + x: svgCanvas.getRStartX(), + y: svgCanvas.getRStartY(), + width: 0, + height: 0, + display: 'inline' + }, 100) + } + break + case 'zoom': + svgCanvas.setStarted(true) + if (!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 'zoom': - eventContext_.setStarted(true); - if (isNullish(eventContext_.getRubberBox())) { - eventContext_.setRubberBox(svgCanvas.selectorManager.getRubberBandBox()); - } - assignAttributes(eventContext_.getRubberBox(), { - x: realX * currentZoom, - y: realX * currentZoom, - width: 0, - height: 0, - display: 'inline' - }, 100); - break; - case 'resize': { - eventContext_.setStarted(true); - eventContext_.setStartX(x); - eventContext_.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 - eventContext_.setInitBbox(utilsGetBBox($id('selectedBox0'))); - const bb = {}; - for (const [ key, val ] of Object.entries(eventContext_.getInitBbox())) { - bb[key] = val / currentZoom; - } - eventContext_.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': - eventContext_.setStart({ x: realX, y: realY }); - eventContext_.setControllPoint1('x', 0); - eventContext_.setControllPoint1('y', 0); - eventContext_.setControllPoint2('x', 0); - eventContext_.setControllPoint2('y', 0); - eventContext_.setStarted(true); - eventContext_.setDAttr(realX + ',' + realY + ' '); - // Commented out as doing nothing now: - // strokeW = parseFloat(curShape.stroke_width) === 0 ? 1 : curShape.stroke_width; - svgCanvas.addSVGElementFromJson({ - element: 'polyline', - curStyles: true, - attr: { - points: eventContext_.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 } - }); - eventContext_.setFreehand('minx', realX); - eventContext_.setFreehand('maxx', realX); - eventContext_.setFreehand('miny', realY); - eventContext_.setFreehand('maxy', realY); - break; - case 'image': { - eventContext_.setStarted(true); - const newImage = svgCanvas.addSVGElementFromJson({ - 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, eventContext_.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.addSVGElementsFromJson({ + 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.addSVGElementsFromJson({ + 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': - eventContext_.setStarted(true); - eventContext_.setStartX(x); - eventContext_.setStartY(y); - svgCanvas.addSVGElementFromJson({ - element: 'rect', - curStyles: true, - attr: { - x, - y, - width: 0, - height: 0, - id: svgCanvas.getNextId(), - opacity: curShape.opacity / 2 - } - }); - break; - case 'line': { - eventContext_.setStarted(true); - const strokeW = Number(curShape.stroke_width) === 0 ? 1 : curShape.stroke_width; - svgCanvas.addSVGElementFromJson({ - 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': - eventContext_.setStarted(true); - svgCanvas.addSVGElementFromJson({ - element: 'circle', - curStyles: true, - attr: { - cx: x, - cy: y, - r: 0, - id: svgCanvas.getNextId(), - opacity: curShape.opacity / 2 - } - }); - break; - case 'ellipse': - eventContext_.setStarted(true); - svgCanvas.addSVGElementFromJson({ - element: 'ellipse', - curStyles: true, - attr: { - cx: x, - cy: y, - rx: 0, - ry: 0, - id: svgCanvas.getNextId(), - opacity: curShape.opacity / 2 - } - }); - break; - case 'text': - eventContext_.setStarted(true); - /* const newText = */ svgCanvas.addSVGElementFromJson({ - element: 'text', - curStyles: true, - attr: { - x, - y, - id: svgCanvas.getNextId(), - fill: eventContext_.getCurText('fill'), - 'stroke-width': eventContext_.getCurText('stroke_width'), - 'font-size': eventContext_.getCurText('font_size'), - 'font-family': eventContext_.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.addSVGElementsFromJson({ + 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.addSVGElementsFromJson({ + 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.addSVGElementsFromJson({ + 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.addSVGElementsFromJson({ + 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.addSVGElementsFromJson({ + 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': - eventContext_.setStartX(eventContext_.getStartX() * currentZoom); - eventContext_.setStartY(eventContext_.getStartY() * currentZoom); - svgCanvas.pathActions.mouseDown(evt, mouseTarget, eventContext_.getStartX(), eventContext_.getStartY()); - eventContext_.setStarted(true); - break; - case 'textedit': - eventContext_.setStartX(eventContext_.getStartX() * currentZoom); - eventContext_.setStartY(eventContext_.getStartY() * currentZoom); - svgCanvas.textActions.mouseDown(evt, mouseTarget, eventContext_.getStartX(), eventContext_.getStartY()); - eventContext_.setStarted(true); - break; - case 'rotate': - eventContext_.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; + 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 } /** @@ -1286,102 +1284,100 @@ export const mouseDownEvent = function (evt) { */ const extResult = svgCanvas.runExtensions('mouseDown', { event: evt, - start_x: eventContext_.getStartX(), - start_y: eventContext_.getStartY(), - selectedElements: selectedElements() - }, true); + start_x: svgCanvas.getStartX(), + start_y: svgCanvas.getStartY(), + selectedElements + }, true) - extResult.forEach(function(r){ - if (r && r.started) { - eventContext_.setStarted(true); + extResult.forEach((r) => { + if (r?.started) { + svgCanvas.setStarted(true) } - }); -}; + }) +} /** * @param {Event} e * @fires module:event.SvgCanvas#event:updateCanvas * @fires module:event.SvgCanvas#event:zoomDone * @returns {void} */ -export const DOMMouseScrollEvent = function (e) { - const currentZoom = eventContext_.getCurrentZoom(); - const svgCanvas = eventContext_.getCanvas(); - const { $id } = svgCanvas; - if (!e.shiftKey) { return; } +const DOMMouseScrollEvent = (e) => { + const zoom = svgCanvas.getZoom() + const { $id } = svgCanvas + if (!e.shiftKey) { return } - e.preventDefault(); - const evt = e.originalEvent; + e.preventDefault() - eventContext_.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 = eventContext_.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(evt.clientX, evt.clientY, eventContext_.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 * eventContext_.getrootSctm().a; - const workareaViewH = editorH * eventContext_.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 = (evt.wheelDelta) ? evt.wheelDelta : (evt.detail) ? -evt.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)); - if (zoomlevel === currentZoom) { - return; + let zoomlevel = Math.min(wZoom, hZoom) + zoomlevel = Math.min(10, Math.max(0.01, zoomlevel)) + if (zoomlevel === zoom) { + return } - factor = zoomlevel / currentZoom; + factor = zoomlevel / zoom // top left of workarea in content pixels before zoom - const topLeftOld = transformPoint(wOffsetLeft, wOffsetTop, eventContext_.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 6e0b5310..891f4e8b 100644 --- a/src/svgcanvas/history.js +++ b/src/svgcanvas/history.js @@ -6,7 +6,7 @@ * @copyright 2010 Jeff Schiller */ -import { getHref, setHref, getRotationAngle, isNullish } from './utilities.js'; +import { getHref, setHref, getRotationAngle, 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() + }) } /** @@ -255,11 +255,11 @@ export class RemoveElementCommand extends Command { */ unapply (handler) { super.unapply(handler, () => { - if (isNullish(this.nextSibling) && window.console) { - console.error('Reference element was lost'); + if (!this.nextSibling) { + 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 = this.elem.getBBox(); - 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 = this.elem.getBBox(); - 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 (!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 (!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 deleted file mode 100644 index f5178a82..00000000 --- a/src/svgcanvas/jQuery.attr.js +++ /dev/null @@ -1,79 +0,0 @@ -/** - * A jQuery module to work with SVG attributes. - * @module jQueryAttr - * @license MIT - */ - -/** -* This fixes `$(...).attr()` to work as expected with SVG elements. -* Does not currently use `*AttributeNS()` since we rarely need that. -* Adds {@link external:jQuery.fn.attr}. -* See {@link https://api.jquery.com/attr/} for basic documentation of `.attr()`. -* -* Additional functionality: -* - When getting attributes, a string that's a number is returned as type number. -* - If an array is supplied as the first parameter, multiple values are returned -* as an object with values for each given attribute. -* @function module:jQueryAttr.jQueryAttr -* @param {external:jQuery} $ The jQuery object to which to add the plug-in -* @returns {external:jQuery} -*/ -export default function jQueryPluginSVG ($) { - const proxied = $.fn.attr; - const svgns = 'http://www.w3.org/2000/svg'; - /** - * @typedef {PlainObject} module:jQueryAttr.Attributes - */ - /** - * @function external:jQuery.fn.attr - * @param {string|string[]|PlainObject} key - * @param {string} value - * @returns {external:jQuery|module:jQueryAttr.Attributes} - */ - $.fn.attr = function (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]; - // set/get SVG attribute - if (elem.namespaceURI === svgns) { - // Setting attribute - if (value !== undefined) { - elem.setAttribute(key, value); - } else if (Array.isArray(key)) { - // Getting attributes from array - const obj = {}; - let j = key.length; - - while (j--) { - 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); - } - obj[aname] = attr; - } - return obj; - } - if (typeof key === 'object') { - // Setting attributes from object - for (const [ name, val ] of Object.entries(key)) { - elem.setAttribute(name, val); - } - // Getting attribute - } else { - let attr = elem.getAttribute(key); - if (attr || attr === '0') { - attr = isNaN(attr) ? attr : (attr - 0); - } - return attr; - } - } else { - return proxied.call(this, key, value); - } - } - return this; - }; - return $; -} diff --git a/src/svgcanvas/json.js b/src/svgcanvas/json.js index 41253ff2..80be6896 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 '../common/namespaces.js'; +import { getElement, assignAttributes, cleanupElement } from './utilities.js' +import { NS } from './namespaces.js' -let jsonContext_ = null; -let svgdoc_ = null; +let svgCanvas = null +let svgdoc_ = null /** * @function module:json.jsonContext#getSelectedElements @@ -25,10 +25,10 @@ let svgdoc_ = null; * @param {module:json.jsonContext} jsonContext * @returns {void} */ -export const init = function (jsonContext) { - jsonContext_ = jsonContext; - svgdoc_ = jsonContext.getDOMDocument(); -}; +export const init = (canvas) => { + svgCanvas = canvas + svgdoc_ = canvas.getDOMDocument() +} /** * @function module:json.getJsonFromSvgElements Iterate element and return json format * @param {ArgumentsArray} data - element @@ -36,57 +36,57 @@ export const init = function (jsonContext) { */ 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. * @name module:json.addSVGElementsFromJson -* @type {module:utilities.EditorContext#addSVGElementsFromJson|module:path.EditorContext#addSVGElementFromJson} +* @type {module:utilities.EditorContext#addSVGElementsFromJson|module:path.EditorContext#addSVGElementsFromJson} */ -export const addSVGElementsFromJson = function (data) { - if (typeof data === 'string') return svgdoc_.createTextNode(data); +export const addSVGElementsFromJson = (data) => { + if (typeof data === 'string') return svgdoc_.createTextNode(data) - let shape = getElem(data.attr.id); + let shape = getElement(data.attr.id) // if shape is a path but we need to create a rect/ellipse, then remove the path - const currentLayer = jsonContext_.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) { - (jsonContext_.getCurrentGroup() || currentLayer).append(shape); + (svgCanvas.getCurrentGroup() || currentLayer).append(shape) } } - const curShape = jsonContext_.getCurShape(); + const curShape = svgCanvas.getCurShape() if (data.curStyles) { assignAttributes(shape, { fill: curShape.fill, stroke: curShape.stroke, - 'stroke-width': curShape.stroke_width, + 'stroke-width': curShape.strokeWidth, 'stroke-dasharray': curShape.stroke_dasharray, 'stroke-linejoin': curShape.stroke_linejoin, 'stroke-linecap': curShape.stroke_linecap, @@ -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 e238a72a..fe87fbfb 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 '../common/namespaces.js'; -import { toXml, walkTree, isNullish } from './utilities.js'; - +import { NS } from './namespaces.js' +import { toXml, walkTree } 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'); - if (isNullish(opacity)) { - return 1; + const opacity = this.group_.getAttribute('opacity') + if (!opacity) { + 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); - if (child && child.tagName === 'title') { - return child; + const child = this.group_.childNodes.item(i) + if (child?.tagName === 'title') { + 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'); - if (isNullish(classes) || !classes.length) { - elem.setAttribute('class', Layer.CLASS_NAME); + const classes = elem.getAttribute('class') + if (!classes || !classes.length) { + 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 69da0cc3..080e33ae 100644 --- a/src/svgcanvas/math.js +++ b/src/svgcanvas/math.js @@ -19,13 +19,13 @@ * @property {Float} y */ -import { NS } from '../common/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. @@ -176,10 +176,10 @@ export const transformListToTransform = function (tlist, min, max) { * @param {Element} elem - The DOM element to check * @returns {SVGMatrix} The matrix object associated with the element's transformlist */ -export const getMatrix = function (elem) { - const tlist = elem.transform.baseVal; - return transformListToTransform(tlist).matrix; -}; +export const getMatrix = (elem) => { + const tlist = elem.transform.baseVal + return transformListToTransform(tlist).matrix +} /** * Returns a 45 degree angle coordinate associated with the two given @@ -191,20 +191,20 @@ export const getMatrix = function (elem) { * @param {Integer} y2 - Second coordinate's y value * @returns {module:math.AngleCoord45} */ -export const snapToAngle = function (x1, y1, x2, y2) { - const snap = Math.PI / 4; // 45 degrees - const dx = x2 - x1; - const dy = y2 - y1; - const angle = Math.atan2(dy, dx); - const dist = Math.sqrt(dx * dx + dy * dy); - const snapangle = Math.round(angle / snap) * snap; +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 return { x: x1 + dist * Math.cos(snapangle), y: y1 + dist * Math.sin(snapangle), a: snapangle - }; -}; + } +} /** * Check if two rectangles (BBoxes objects) intersect each other. @@ -213,9 +213,9 @@ export const snapToAngle = function (x1, y1, x2, y2) { * @param {SVGRect} r2 - The second BBox-like object * @returns {boolean} True if rectangles intersect */ -export const rectsIntersect = function (r1, r2) { +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/common/namespaces.js b/src/svgcanvas/namespaces.js similarity index 88% rename from src/common/namespaces.js rename to src/svgcanvas/namespaces.js index 3771691a..5dae4684 100644 --- a/src/common/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 b71e94d1..cbe1bdf0 100644 --- a/src/svgcanvas/paste-elem.js +++ b/src/svgcanvas/paste-elem.js @@ -1,22 +1,22 @@ 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 pasteContext_ = null; +let svgCanvas = null /** * @function module:paste-elem.init * @param {module:paste-elem.pasteContext} pasteContext * @returns {void} */ -export const init = function (pasteContext) { - pasteContext_ = pasteContext; -}; +export const init = (canvas) => { + svgCanvas = canvas +} /** * @function module:svgcanvas.SvgCanvas#pasteElements @@ -28,13 +28,13 @@ export const init = function (pasteContext) { * @returns {void} */ export const pasteElementsMethod = function (type, x, y) { - let clipb = JSON.parse(sessionStorage.getItem(pasteContext_.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 /** @@ -51,13 +51,13 @@ export const pasteElementsMethod = function (type, x, y) { * @returns {void} */ function checkIDs (elem) { - if (elem.attr && elem.attr.id) { - changedIDs[elem.attr.id] = pasteContext_.getCanvas().getNextId(); - elem.attr.id = changedIDs[elem.attr.id]; + if (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 /** @@ -67,61 +67,61 @@ export const pasteElementsMethod = function (type, x, y) { * @property {module:svgcanvas.SVGAsJSON[]} elems * @property {module:svgcanvas.ChangedIDs} changes Maps past ID (on attribute) to current ID */ - pasteContext_.getCanvas().runExtensions( + svgCanvas.runExtensions( 'IDsUpdated', /** @type {module:svgcanvas.SvgCanvas#event:ext_IDsUpdated} */ { 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 = pasteContext_.getCanvas().addSVGElementFromJson(elem); - pasted.push(copy); - batchCmd.addSubCommand(new InsertElementCommand(copy)); + const copy = svgCanvas.addSVGElementsFromJson(elem) + pasted.push(copy) + batchCmd.addSubCommand(new InsertElementCommand(copy)) - pasteContext_.restoreRefElems(copy); + svgCanvas.restoreRefElements(copy) } - pasteContext_.getCanvas().selectOnly(pasted); + svgCanvas.selectOnly(pasted) if (type !== 'in_place') { - let ctrX; let ctrY; + let ctrX; let ctrY if (!type) { - ctrX = pasteContext_.getLastClickPoint('x'); - ctrY = pasteContext_.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 = pasteContext_.getCanvas().moveSelectedElements(dx, dy, false); - if (cmd) batchCmd.addSubCommand(cmd); + const cmd = svgCanvas.moveSelectedElements(dx, dy, false) + if (cmd) batchCmd.addSubCommand(cmd) } - pasteContext_.addCommandToHistory(batchCmd); - pasteContext_.getCanvas().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 b4a1c6e0..720b7390 100644 --- a/src/svgcanvas/path-actions.js +++ b/src/svgcanvas/path-actions.js @@ -6,35 +6,29 @@ * @copyright 2011 Alexis Deveria, 2011 Jeff Schiller */ -import { NS } from '../common/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 as utilsGetBBox -} from './utilities.js'; -import { - isWebkit -} from '../common/browser.js'; + assignAttributes, getElement, getRotationAngle, snapToGrid, + getBBox +} from './utilities.js' -let pathActionsContext_ = null; -let editorContext_ = null; -let path = null; +let svgCanvas = null +let path = null /** * @function module:path-actions.init -* @param {module:path-actions.pathActionsContext_} pathActionsContext +* @param {module:path-actions.svgCanvas} pathActionsContext * @returns {void} */ -export const init = function (pathActionsContext) { - pathActionsContext_ = pathActionsContext; - // editorContext_ = pathActionsContext_.getEditorContext(); - // path = pathActionsContext_.getPathObj(); -}; +export const init = (canvas) => { + svgCanvas = canvas +} /** * Convert a path to one with only absolute or relative values. @@ -45,160 +39,174 @@ export const init = function (pathActionsContext) { * @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 = pathActionsContext_.getPathMap(); - let letter = pathMap[type][toRel ? 'toLowerCase' : 'toUpperCase'](); + // const type = seg.pathSegType; + // const pathMap = svgCanvas.getPathMap(); + // let letter = pathMap[type][toRel ? 'toLowerCase' : 'toUpperCase'](); + let letter = seg.pathSegTypeAsLetter - 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; + 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 // 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 '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 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 '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 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 '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 6: // 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 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 '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 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 '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 // 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; - // 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 '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. @@ -210,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 } /** @@ -230,13 +238,13 @@ 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; - // No `editorContext_` yet but should be ok as is `null` by default - // editorContext_.setDrawnPath(null); + let currentPath = null + let hasMoved = false + // No `svgCanvas` yet but should be ok as is `null` by default + // svgCanvas.setDrawnPath(null); /** * This function converts a polyline (created by the fh_path tool) into @@ -247,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 // @@ -264,56 +272,54 @@ 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 = pathActionsContext_.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 newpts = svgCanvas.smoothControlPoints(prevCtlPt, ct1, curpos) + if (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] } } - 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(' ') - // create new path element - editorContext_ = pathActionsContext_.getEditorContext(); - element = editorContext_.addSVGElementFromJson({ + element = svgCanvas.addSVGElementsFromJson({ element: 'path', curStyles: true, attr: { - id: editorContext_.getId(), + id: svgCanvas.getId(), d, fill: 'none' } - }); + }) // No need to call "changed", as this is already done under mouseUp } - return element; - }; + return element + } return (/** @lends module:path.pathActions */ { /** @@ -324,85 +330,84 @@ export const pathActionsMethod = (function () { * @returns {boolean|void} */ mouseDown (evt, mouseTarget, startX, startY) { - let id; - editorContext_ = pathActionsContext_.getEditorContext(); - if (editorContext_.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 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) - const currentZoom = editorContext_.getCurrentZoom(); - let x = mouseX / currentZoom; - let y = mouseY / currentZoom; - let stretchy = getElem('path_stretch_line'); - newPoint = [ x, y ]; + const zoom = svgCanvas.getZoom() + let x = mouseX / zoom + let y = mouseY / zoom + let stretchy = getElement('path_stretch_line') + newPoint = [x, y] - if (editorContext_.getGridSnapping()) { - x = snapToGrid(x); - y = snapToGrid(y); - mouseX = snapToGrid(mouseX); - mouseY = snapToGrid(mouseY); + if (svgCanvas.getGridSnapping()) { + 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); + }) + getElement('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 = editorContext_.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) - /* drawnPath = */ editorContext_.setDrawnPath(editorContext_.addSVGElementFromJson({ + 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.addSVGElementsFromJson({ element: 'path', curStyles: true, attr: { d: dAttr, - id: editorContext_.getNextId(), - opacity: editorContext_.getOpacity() / 2 + 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; - pathActionsContext_.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 / currentZoom; - 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 = editorContext_.getId(); + id = svgCanvas.getId() // Remove previous path object if previously created - pathActionsContext_.removePath_(id); + svgCanvas.removePath_(id) - const newpath = getElem(id); - let newseg; - let sSeg; - const len = seglist.numberOfItems; + const newpath = getElement(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) { @@ -412,146 +417,145 @@ 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 / currentZoom, sSeg.y1 / currentZoom, 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 = */ editorContext_.setDrawnPath(null); - editorContext_.setStarted(false); + /* drawnPath = */ svgCanvas.setDrawnPath(null) + svgCanvas.setStarted(false) if (subpath) { if (path.matrix) { - editorContext_.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) { - pathActionsContext_.recalcRotatedPath(); + svgCanvas.recalcRotatedPath() } - init(); - 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 { // Checks if current target or parents are #svgcontent - if (!(editorContext_.getContainer() !== editorContext_.getMouseTarget(evt) && editorContext_.getContainer().contains( - editorContext_.getMouseTarget(evt) + if (!(svgCanvas.getContainer() !== svgCanvas.getMouseTarget(evt) && svgCanvas.getContainer().contains( + 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(editorContext_.round(x), editorContext_.round(y)) + ? drawnPath.createSVGPathSegLinetoAbs(svgCanvas.round(x), svgCanvas.round(y)) : drawnPath.createSVGPathSegCurvetoCubicAbs( - editorContext_.round(x), - editorContext_.round(y), - sSeg.x1 / currentZoom, - sSeg.y1 / currentZoom, - sSeg.x2 / currentZoom, - sSeg.y2 / currentZoom - ); + svgCanvas.round(x), + svgCanvas.round(y), + sSeg.x1 / zoom, + sSeg.y1 / zoom, + sSeg.x2 / zoom, + sSeg.y2 / zoom + ) - drawnPath.pathSegList.appendItem(newseg); + drawnPath.pathSegList.appendItem(newseg) - x *= currentZoom; - y *= currentZoom; + 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; } - pathActionsContext_.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 = editorContext_.getRubberBox(); - if (isNullish(rubberBox)) { - rubberBox = editorContext_.setRubberBox( - editorContext_.selectorManager.getRubberBandBox() - ); + let rubberBox = svgCanvas.getRubberBox() + if (!rubberBox) { + rubberBox = svgCanvas.setRubberBox( + svgCanvas.selectorManager.getRubberBandBox() + ) } - const currentZoom = editorContext_.getCurrentZoom(); + const zoom = svgCanvas.getZoom() assignAttributes(rubberBox, { - x: startX * currentZoom, - y: startY * currentZoom, + x: startX * zoom, + y: startY * zoom, width: 0, height: 0, display: 'inline' - }, 100); + }, 100) } - return undefined; + return undefined }, /** * @param {Float} mouseX @@ -559,132 +563,131 @@ export const pathActionsMethod = (function () { * @returns {void} */ mouseMove (mouseX, mouseY) { - editorContext_ = pathActionsContext_.getEditorContext(); - const currentZoom = editorContext_.getCurrentZoom(); - hasMoved = true; - const drawnPath = editorContext_.getDrawnPath(); - if (editorContext_.getCurrentMode() === 'path') { - if (!drawnPath) { return; } - const seglist = drawnPath.pathSegList; - const index = seglist.numberOfItems - 1; + 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 (newPoint) { // First point // if (!index) { return; } // Set control points - const pointGrip1 = pathActionsContext_.addCtrlGrip('1c1'); - const pointGrip2 = pathActionsContext_.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 / currentZoom; - const curY = mouseY / currentZoom; - 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 * currentZoom); - pointGrip2.setAttribute('cy', altY * currentZoom); - pointGrip2.setAttribute('display', 'inline'); + pointGrip2.setAttribute('cx', altX * zoom) + pointGrip2.setAttribute('cy', altY * zoom) + pointGrip2.setAttribute('display', 'inline') - const ctrlLine = pathActionsContext_.getCtrlLine(1); + const ctrlLine = svgCanvas.getCtrlLine(1) assignAttributes(ctrlLine, { x1: mouseX, y1: mouseY, - x2: altX * currentZoom, - y2: altY * currentZoom, + 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] / currentZoom; - lastY = firstCtrl[1] / currentZoom; + lastX = firstCtrl[0] / zoom + lastY = firstCtrl[1] / zoom } - pathActionsContext_.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 = getElement('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); - pathActionsContext_.replacePathSeg( + const prevX = prev.x + (prev.x - prev.x2) + const prevY = prev.y + (prev.y - prev.y2) + svgCanvas.replacePathSeg( 6, 1, - [ mouseX, mouseY, prevX * currentZoom, prevY * currentZoom, mouseX, mouseY ], + [mouseX, mouseY, prevX * zoom, prevY * zoom, mouseX, mouseY], stretchy - ); + ) } else if (firstCtrl) { - pathActionsContext_.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 { - pathActionsContext_.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 = pathActionsContext_.getPointFromGrip({ + const pt = svgCanvas.getPointFromGrip({ x: path.dragging[0], y: path.dragging[1] - }, path); - const mpt = pathActionsContext_.getPointFromGrip({ + }, 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 = editorContext_.getRubberBox(); - const rbb = rubberBox.getBBox(); + const rubberBox = svgCanvas.getRubberBox() + const rbb = getBBox(rubberBox) - const pt = pathActionsContext_.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) } + }) } }, /** @@ -701,66 +704,65 @@ export const pathActionsMethod = (function () { * @returns {module:path.keepElement|void} */ mouseUp (evt, element, _mouseX, _mouseY) { - editorContext_ = pathActionsContext_.getEditorContext(); - const drawnPath = editorContext_.getDrawnPath(); + const drawnPath = svgCanvas.getDrawnPath() // Create mode - if (editorContext_.getCurrentMode() === 'path') { - newPoint = null; + if (svgCanvas.getCurrentMode() === 'path') { + newPoint = null if (!drawnPath) { - element = getElem(editorContext_.getId()); - editorContext_.setStarted(false); - firstCtrl = null; + element = getElement(svgCanvas.getId()) + svgCanvas.setStarted(false) + firstCtrl = null } return { keep: true, element - }; + } } // Edit mode - const rubberBox = editorContext_.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') { + } else if (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) { - editorContext_ = pathActionsContext_.getEditorContext(); - path = pathActionsContext_.getPath_(element); - editorContext_.setCurrentMode('pathedit'); - editorContext_.clearSelection(); - path.show(true).update(); - path.oldbbox = utilsGetBBox(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 @@ -768,21 +770,21 @@ export const pathActionsMethod = (function () { * @returns {void} */ toSelectMode (elem) { - editorContext_ = pathActionsContext_.getEditorContext(); - const selPath = (elem === path.elem); - editorContext_.setCurrentMode('select'); - path.show(false); - currentPath = false; - editorContext_.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 - pathActionsContext_.recalcRotatedPath(); + svgCanvas.recalcRotatedPath() } if (selPath) { - editorContext_.call('selected', [ elem ]); - editorContext_.addToSelection([ elem ], true); + svgCanvas.call('selected', [elem]) + svgCanvas.addToSelection([elem], true) } }, /** @@ -790,15 +792,14 @@ export const pathActionsMethod = (function () { * @returns {void} */ addSubPath (on) { - editorContext_ = pathActionsContext_.getEditorContext(); if (on) { // Internally we go into "path" mode, but in the UI it will // still appear as if in "pathedit" mode. - editorContext_.setCurrentMode('path'); - subpath = true; + svgCanvas.setCurrentMode('path') + subpath = true } else { - pathActionsMethod.clear(true); - pathActionsMethod.toEditMode(path.elem); + pathActionsMethod.clear(true) + pathActionsMethod.toEditMode(path.elem) } }, /** @@ -806,13 +807,12 @@ export const pathActionsMethod = (function () { * @returns {void} */ select (target) { - editorContext_ = pathActionsContext_.getEditorContext(); if (currentPath === target) { - pathActionsMethod.toEditMode(target); - editorContext_.setCurrentMode('pathedit'); + pathActionsMethod.toEditMode(target) + svgCanvas.setCurrentMode('pathedit') // going into pathedit mode } else { - currentPath = target; + currentPath = target } }, /** @@ -820,30 +820,29 @@ export const pathActionsMethod = (function () { * @returns {void} */ reorient () { - editorContext_ = pathActionsContext_.getEditorContext(); - const elem = editorContext_.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)); - editorContext_.clearSelection(); - this.resetOrientation(elem); + } + batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)) + svgCanvas.clearSelection() + this.resetOrientation(elem) - editorContext_.addCommandToHistory(batchCmd); + svgCanvas.addCommandToHistory(batchCmd) // Set matrix to null - pathActionsContext_.getPath_(elem).show(false).matrix = null; + svgCanvas.getPath_(elem).show(false).matrix = null - this.clear(); + this.clear() - editorContext_.addToSelection([ elem ], true); - editorContext_.call('changed', editorContext_.getSelectedElements()); + svgCanvas.addToSelection([elem], true) + svgCanvas.call('changed', svgCanvas.getSelectedElements()) }, /** @@ -851,45 +850,44 @@ export const pathActionsMethod = (function () { * @returns {void} */ clear () { - editorContext_ = pathActionsContext_.getEditorContext(); - const drawnPath = editorContext_.getDrawnPath(); - currentPath = null; + const drawnPath = svgCanvas.getDrawnPath() + currentPath = null if (drawnPath) { - const elem = getElem(editorContext_.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.style.display = 'none'; - }); - firstCtrl = null; - editorContext_.setDrawnPath(null); - editorContext_.setStarted(false); - } else if (editorContext_.getCurrentMode() === 'pathedit') { - this.toSelectMode(); + const elem = getElement(svgCanvas.getId()) + const psl = getElement('path_stretch_line') + psl.parentNode.removeChild(psl) + elem.parentNode.removeChild(elem) + const pathpointgripContainer = getElement('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() } - 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 (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); @@ -898,30 +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) } - }); - pathActionsContext_.replacePathSeg(type, i, pts, pth); + }) + svgCanvas.replacePathSeg(type, i, pts, pth) } - pathActionsContext_.reorientGrads(pth, m); - return undefined; + svgCanvas.reorientGrads(pth, m) + return undefined }, /** * @returns {void} */ zoomChange () { - editorContext_ = pathActionsContext_.getEditorContext(); - if (editorContext_.getCurrentMode() === 'pathedit') { - path.update(); + if (svgCanvas.getCurrentMode() === 'pathedit') { + path.update() } }, /** @@ -934,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) { - pathActionsContext_.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)) { + if (!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 { - pathActionsContext_.insertItemBefore(elem, closer, openPt); - pathActionsContext_.insertItemBefore(elem, 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 @@ -1040,130 +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--) { - pathActionsContext_.insertItemBefore(elem, 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" - pathActionsContext_.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); - editorContext_ = pathActionsContext_.getEditorContext(); - editorContext_.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` /** @@ -1178,7 +1174,7 @@ export const pathActionsMethod = (function () { * @returns {void} */ setSegType (v) { - path.setSegType(v); + path?.setSegType(v) }, /** * @param {string} attr @@ -1186,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 @@ -1207,29 +1203,27 @@ 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); - if (item.pathSegType === 2) { - lastM = item; + const item = segList.getItem(i) + if (item.pathSegType === 2) { // 2 => M segment type (move to) + lastM = item } - if (item.pathSegType === 1) { - const prev = segList.getItem(i - 1); + if (item.pathSegType === 1) { // 1 => Z segment type (close path) + 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); - pathActionsContext_.insertItemBefore(elem, 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 } } } - editorContext_ = pathActionsContext_.getEditorContext(); - if (isWebkit()) { editorContext_.resetD(elem); } }, // Can't seem to use `@borrows` here, so using `@see` /** @@ -1238,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 d17c0e7a..52bc1351 100644 --- a/src/svgcanvas/path-method.js +++ b/src/svgcanvas/path-method.js @@ -6,60 +6,27 @@ * @copyright 2011 Alexis Deveria, 2011 Jeff Schiller */ -import { NS } from '../common/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'; -import { - supportsPathInsertItemBefore, supportsPathReplaceItem, isWebkit -} from '../common/browser.js'; + assignAttributes, getRotationAngle, + getElement +} from './utilities.js' -let pathMethodsContext_ = null; -let editorContext_ = null; +let svgCanvas = null /** * @function module:path-actions.init -* @param {module:path-actions.pathMethodsContext_} pathMethodsContext +* @param {module:path-actions.svgCanvas} pathMethodsContext * @returns {void} */ -export const init = function (pathMethodsContext) { - pathMethodsContext_ = pathMethodsContext; -}; +export const init = (canvas) => { + svgCanvas = canvas +} -/** -* @function module:path.insertItemBefore -* @param {Element} elem -* @param {Segment} newseg -* @param {Integer} index -* @returns {void} -*/ -export const insertItemBeforeMethod = function (elem, newseg, index) { - // Support insertItemBefore on paths for FF2 - const list = elem.pathSegList; - - if (supportsPathInsertItemBefore()) { - list.insertItemBefore(newseg, index); - return; - } - const len = list.numberOfItems; - const arr = []; - for (let i = 0; i < len; i++) { - const curSeg = list.getItem(i); - arr.push(curSeg); - } - list.clear(); - for (let i = 0; i < len; i++) { - if (i === index) { // index + 1 - list.appendItem(newseg); - } - list.appendItem(arr[i]); - } -}; /* eslint-disable max-len */ /** * @function module:path.ptObjToArr @@ -70,12 +37,12 @@ export const insertItemBeforeMethod = function (elem, newseg, index) { */ /* eslint-enable max-len */ export const ptObjToArrMethod = function (type, segItem) { - const segData = pathMethodsContext_.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 @@ -84,23 +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 } - editorContext_ = pathMethodsContext_.getEditorContext(); - const currentZoom = editorContext_.getCurrentZoom(); - out.x *= currentZoom; - out.y *= currentZoom; + const zoom = svgCanvas.getZoom() + out.x *= zoom + out.y *= zoom - return out; -}; + return out +} /** * @function module:path.getPointFromGrip * @param {module:math.XYObject} pt @@ -111,34 +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 } - editorContext_ = pathMethodsContext_.getEditorContext(); - const currentZoom = editorContext_.getCurrentZoom(); - out.x /= currentZoom; - out.y /= currentZoom; + 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 = getElement('pathpointgrip_container') if (!c) { - const parentElement = getElem('selectorParentGroup'); - c = document.createElementNS(NS.SVG, 'g'); - parentElement.append(c); - c.id = 'pathpointgrip_container'; + const parentElement = getElement('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. @@ -150,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 = getElement('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', @@ -165,21 +130,21 @@ export const addPointGripMethod = function (index, x, y) { 'stroke-width': 2, cursor: 'move', style: 'pointer-events:all' - }; - const uiStrings = pathMethodsContext_.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 = pathMethodsContext_.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 @@ -187,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. @@ -199,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 = getElement('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', @@ -212,34 +177,34 @@ export const addCtrlGripMethod = function (id) { 'stroke-width': 1, cursor: 'move', style: 'pointer-events:all' - }; - const uiStrings = pathMethodsContext_.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 = getElement('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 @@ -247,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 = pathMethodsContext_.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, @@ -292,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 @@ -318,32 +283,14 @@ export const getControlPointsMethod = function (seg) { * @returns {void} */ export const replacePathSegMethod = function (type, index, pts, elem) { - const path = pathMethodsContext_.getPathObj(); - const pth = elem || path.elem; - const pathFuncs = pathMethodsContext_.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) - if (supportsPathReplaceItem()) { - pth.pathSegList.replaceItem(seg, index); - } else { - const segList = pth.pathSegList; - const len = segList.numberOfItems; - const arr = []; - for (let i = 0; i < len; i++) { - const curSeg = segList.getItem(i); - arr.push(curSeg); - } - segList.clear(); - for (let i = 0; i < len; i++) { - if (i === index) { - segList.appendItem(seg); - } else { - segList.appendItem(arr[i]); - } - } - } -}; + pth.pathSegList.replaceItem(seg, index) +} /** * @function module:path.getSegSelector * @param {Segment} seg @@ -351,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 = getElement('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', @@ -365,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 +} /** * */ @@ -401,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 } /** @@ -418,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') } } } @@ -428,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') } /** @@ -438,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) } } @@ -451,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 } } @@ -464,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) } /** @@ -475,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 = pathMethodsContext_.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'); } @@ -501,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; + if (this.next?.ctrlpts) { + 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) } } /** @@ -544,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) } /** @@ -578,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) } /** @@ -597,13 +544,13 @@ export class Segment { * @returns {void} */ setType (newType, pts) { - replacePathSegMethod(newType, this.index, pts); - this.type = newType; - const path = pathMethodsContext_.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) } } @@ -617,16 +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 = []; - pathMethodsContext_.setPathObj(this); + this.elem = elem + this.segs = [] + this.selected_pts = [] + svgCanvas.setPathObj(this) // path = this; - this.init(); + this.init() + } + + setPathContext () { + svgCanvas.setPathObj(this) } /** @@ -637,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.style.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; - } else if (nextSeg && nextSeg.type === 1) { + startI = i + } else if (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(); - if (isNullish(this.first_seg)) { - this.first_seg = seg; + seg.next.prev = seg + seg.mate = segs[startI] + seg.addGrip() + if (!this.first_seg) { + this.first_seg = seg } } else if (!nextSeg) { if (seg.type !== 1) { // Last seg, doesn't close so add a grip // to last sub-path's first point - const startSeg = segs[startI]; - startSeg.next = segs[startI + 1]; - startSeg.next.prev = startSeg; - startSeg.addGrip(); - seg.addGrip(); + 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 } /** @@ -727,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 } } } @@ -740,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 + } } - } - - insertItemBeforeMethod(this.elem, newseg, index); + const list = this.elem.pathSegList + list.insertItemBefore(newseg, index) } /** @@ -780,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) } } @@ -810,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) } /** @@ -824,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') } /** @@ -844,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 } /** @@ -859,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) } } @@ -872,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); - if (pathMethodsContext_.getLinkControlPts()) { - seg.setLinked(this.dragctrl); + const seg = this.segs[this.selected_pts[0]] + seg.moveCtrl(this.dragctrl, dx, dy) + if (svgCanvas.getLinkControlPts()) { + seg.setLinked(this.dragctrl) } } @@ -884,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 = pathMethodsContext_.getPathObj(); - path.endChanges(text); + const path = svgCanvas.getPathObj() + path.endChanges(text) } /** @@ -955,21 +906,21 @@ export class Path { * @returns {void} */ selectPt (pt, ctrlNum) { - this.clearSelection(); - if (isNullish(pt)) { + this.clearSelection() + if (!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 (pathMethodsContext_.getLinkControlPts()) { - this.segs[pt].setLinked(ctrlNum); + if (svgCanvas.getLinkControlPts()) { + this.segs[pt].setLinked(ctrlNum) } } } @@ -979,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 } /** @@ -1001,9 +952,8 @@ export class Path { * @returns {void} */ endChanges (text) { - if (isWebkit()) { editorContext_.resetD(this.elem); } - const cmd = new ChangeElementCommand(this.elem, { d: this.last_d }, text); - editorContext_.endChanges({ cmd, elem: this.elem }); + const cmd = new ChangeElementCommand(this.elem, { d: this.last_d }, text) + svgCanvas.endChanges({ cmd, elem: this.elem }) } /** @@ -1011,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]); - editorContext_.addPtsToSelection({ grips, closedSubpath }); + const closedSubpath = Path.subpathIsClosed(this.selected_pts[0]) + svgCanvas.addPtsToSelection({ grips, closedSubpath }) } // STATIC @@ -1040,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 = pathMethodsContext_.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 f5399591..5ce3b075 100644 --- a/src/svgcanvas/path.js +++ b/src/svgcanvas/path.js @@ -6,76 +6,75 @@ * @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, + getRefElem, findDefs, getBBox as utilsGetBBox -} from './utilities.js'; +} from './utilities.js' import { - init as pathMethodInit, insertItemBeforeMethod, ptObjToArrMethod, getGripPtMethod, + 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 /** * @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 = function (strs) { - Object.assign(uiStrings, strs.ui); -}; +export const setUiStrings = (strs) => { + 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 * @param {boolean} lcp * @returns {void} */ -export const setLinkControlPoints = function (lcp) { - linkControlPts = lcp; -}; +export const setLinkControlPoints = (lcp) => { + linkControlPts = lcp +} /** * @name module:path.path * @type {null|module:path.Path} * @memberof module:path */ -export let path = null; - -let editorContext_ = null; +export let path = null /** * @external MouseEvent @@ -86,7 +85,7 @@ let editorContext_ = null; * @typedef {PlainObject} module:path.SVGElementJSON * @property {string} element - Tag name of the SVG element to create * @property {PlainObject} attr - Has key-value attributes to assign to the new element. -* An `id` should be set so that {@link module:utilities.EditorContext#addSVGElementFromJson} can later re-identify the element for modification or replacement. +* An `id` should be set so that {@link module:utilities.EditorContext#addSVGElementsFromJson} can later re-identify the element for modification or replacement. * @property {boolean} [curStyles=false] - Indicates whether current style attributes should be applied first * @property {module:path.SVGElementJSON[]} [children] - Data objects to be added recursively as children * @property {string} [namespace="http://www.w3.org/2000/svg"] - Indicate a (non-SVG) namespace @@ -103,16 +102,11 @@ let editorContext_ = null; * If the event is "changed", an array of `Element`s is passed; if "selected", a single-item array of `Element` is passed. * @returns {void} */ -/** - * @function module:path.EditorContext#resetD - * @param {SVGPathElement} p - * @returns {void} -*/ /** * Note: This doesn't round to an integer necessarily. * @function module:path.EditorContext#round * @param {Float} val - * @returns {Float} Rounded value to nearest value based on `currentZoom` + * @returns {Float} Rounded value to nearest value based on `zoom` */ /** * @function module:path.EditorContext#clearSelection @@ -138,7 +132,7 @@ let editorContext_ = null; * @returns {void} */ /** - * @function module:path.EditorContext#addSVGElementFromJson + * @function module:path.EditorContext#addSVGElementsFromJson * @param {module:path.SVGElementJSON} data * @returns {Element} The new element */ @@ -187,7 +181,7 @@ let editorContext_ = null; * @returns {void} */ /** - * @function module:path.EditorContext#getCurrentZoom + * @function module:path.EditorContext#getZoom * @returns {Float} The current zoom level */ /** @@ -215,17 +209,13 @@ let editorContext_ = null; * @param {string} cm The mode * @returns {string} The same mode as passed in */ -/** - * @function module:path.EditorContext#getDrawnPath - * @returns {SVGPathElement|null} - */ /** * @function module:path.EditorContext#setDrawnPath * @param {SVGPathElement|null} dp * @returns {SVGPathElement|null} The same value as passed in */ /** - * @function module:path.EditorContext#getSVGRoot + * @function module:path.EditorContext#getSvgRoot * @returns {SVGSVGElement} */ @@ -234,43 +224,37 @@ let editorContext_ = null; * @param {module:path.EditorContext} editorContext * @returns {void} */ -export const init = function (editorContext) { - editorContext_ = editorContext; - - pathFuncs = [ 0, 'ClosePath' ]; +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'] const pathFuncsStrs = [ 'Moveto', 'Lineto', 'CurvetoCubic', 'CurvetoQuadratic', 'Arc', 'LinetoHorizontal', 'LinetoVertical', 'CurvetoCubicSmooth', 'CurvetoQuadraticSmooth' - ]; - pathFuncsStrs.forEach(function(s){ - pathFuncs.push(s + 'Abs'); - pathFuncs.push(s + 'Rel'); - }); -}; + ] + pathFuncsStrs.forEach((s) => { + pathFuncs.push(s + 'Abs') + pathFuncs.push(s + 'Rel') + }) + pathActionsInit(svgCanvas) + pathMethodInit(svgCanvas) +} -pathMethodInit( - /** -* @implements {module:path-method.pathMethodsContext} -*/ - { - getEditorContext () { return editorContext_; }, - getSegData () { return segData; }, - getUIStrings () { return uiStrings; }, - getPathObj () { return path; }, - setPathObj (obj) { path = obj; }, - getPathFuncs () { return pathFuncs; }, - getLinkControlPts () { return linkControlPts; } - } -); - -/** -* @function module:path.insertItemBefore -* @param {Element} elem -* @param {Segment} newseg -* @param {Integer} index -* @returns {void} -*/ -export const insertItemBefore = insertItemBeforeMethod; /* eslint-disable max-len */ /** * @function module:path.ptObjToArr @@ -280,7 +264,7 @@ export const insertItemBefore = insertItemBeforeMethod; * @returns {ArgumentsArray} */ /* eslint-enable max-len */ -export const ptObjToArr = ptObjToArrMethod; +export const ptObjToArr = ptObjToArrMethod /** * @function module:path.getGripPt @@ -288,7 +272,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 @@ -296,7 +280,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` @@ -307,13 +291,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` @@ -322,14 +306,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 @@ -337,14 +321,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. @@ -355,7 +339,7 @@ export const getControlPoints = getControlPointsMethod; * @param {SVGPathElement} elem * @returns {void} */ -export const replacePathSeg = replacePathSegMethod; +export const replacePathSeg = replacePathSegMethod /** * @function module:path.getSegSelector @@ -363,7 +347,7 @@ export const replacePathSeg = replacePathSegMethod; * @param {boolean} update * @returns {SVGPathElement} */ -export const getSegSelector = getSegSelectorMethod; +export const getSegSelector = getSegSelectorMethod /** * @typedef {PlainObject} Point @@ -379,94 +363,96 @@ export const getSegSelector = getSegSelectorMethod; * @param {Point} pt - Object with x and y values (third point) * @returns {Point[]} Array of two "smoothed" point objects */ -export const smoothControlPoints = function (ct1, ct2, pt) { +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 = editorContext_.getSVGRoot().createSVGPoint(); - const nct2 = editorContext_.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_ * @param {SVGPathElement} elem * @returns {module:path.Path} */ -export const getPath_ = function (elem) { - let p = pathData[elem.id]; +export const getPath_ = (elem) => { + 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_ * @param {string} id * @returns {void} */ -export const removePath_ = function (id) { - if (id in pathData) { delete pathData[id]; } -}; +export const removePath_ = (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 = function (x, y) { - let dx = x - oldcx; - let dy = y - oldcy; +const getRotVals = (x, y) => { + 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 @@ -479,56 +465,56 @@ const getRotVals = function (x, y) { * be optimized or even taken care of by `recalculateDimensions` * @returns {void} */ -export const recalcRotatedPath = function () { - const currentPath = path.elem; - angle = getRotationAngle(currentPath, true); - if (!angle) { return; } +export const recalcRotatedPath = () => { + 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 ]; - 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 rvals = getRotVals(seg.x, seg.y) + const points = [rvals.x, rvals.y] + if (seg.x1 && 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) } - 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 = editorContext_.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 @@ -537,9 +523,9 @@ export const recalcRotatedPath = function () { * @function module:path.clearData * @returns {void} */ -export const clearData = function () { - pathData = {}; -}; +export const clearData = () => { + pathData = {} +} // Making public for mocking /** @@ -548,28 +534,28 @@ export const clearData = function () { * @param {SVGMatrix} m * @returns {void} */ -export const reorientGrads = function (elem, m) { - const bb = utilsGetBBox(elem); +export const reorientGrads = (elem, m) => { + 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 = { @@ -577,19 +563,19 @@ export const reorientGrads = function (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 = editorContext_.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. @@ -599,7 +585,7 @@ export const reorientGrads = function (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. @@ -609,160 +595,160 @@ const pathMap = [ * @param {boolean} toRel - true of convert to relative * @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; +export const convertPath = (pth, toRel) => { + 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. @@ -773,46 +759,23 @@ export const convertPath = function (pth, toRel) { * @param {Integer[]} [lastPoint] - x,y point * @returns {string} */ -function pathDSegment (letter, points, morePoints, lastPoint) { - points.forEach(function(pnt, i){ - points[i] = shortFloat(pnt); - }); - let segment = letter + points.join(' '); +const pathDSegment = (letter, points, morePoints, lastPoint) => { + points.forEach((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 } -pathActionsInit( - /** -* @implements {module:path-actions.pathActionsContext} -*/ - { - getEditorContext () { return editorContext_; }, - getPathMap () { return pathMap; }, - smoothControlPoints, - addPointGrip, - recalcRotatedPath, - removePath_, - addCtrlGrip, - getCtrlLine, - replacePathSeg, - insertItemBefore, - getPointFromGrip, - getGripPt, - getPath_, - reorientGrads, - setLinkControlPoints - } -); - /** * 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 bfe33afc..57283e8c 100644 --- a/src/svgcanvas/recalculate.js +++ b/src/svgcanvas/recalculate.js @@ -4,27 +4,26 @@ * @license MIT */ -import { NS } from '../common/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 { getRotationAngle, getHref, getBBox, getRefElem } 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 context_; +let svgCanvas /** * @interface module:recalculate.EditorContext */ /** - * @function module:recalculate.EditorContext#getSVGRoot + * @function module:recalculate.EditorContext#getSvgRoot * @returns {SVGSVGElement} The root DOM element */ /** @@ -42,9 +41,9 @@ let context_; * @param {module:recalculate.EditorContext} editorContext * @returns {void} */ -export const init = function (editorContext) { - context_ = editorContext; -}; +export const init = (canvas) => { + svgCanvas = canvas +} /** * Updates a ``s values based on the given translation of an element. @@ -54,17 +53,17 @@ export const init = function (editorContext) { * @param {Float} ty - The translation's y value * @returns {void} */ -export const updateClipPath = function (attr, tx, ty) { - const path = getRefElem(attr).firstChild; - const cpXform = path.transform.baseVal; - const newxlate = context_.getSVGRoot().createSVGTransform(); - newxlate.setTranslate(tx, ty); +export const updateClipPath = (attr, 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. @@ -72,19 +71,19 @@ export const updateClipPath = function (attr, tx, ty) { * @param {Element} selected - The DOM element to recalculate * @returns {Command} Undo command object with the resulting change */ -export const recalculateDimensions = function (selected) { - if (!selected) return null; - const svgroot = context_.getSVGRoot(); - const dataStorage = context_.getDataStorage(); - const tlist = selected.transform?.baseVal; +export const recalculateDimensions = (selected) => { + 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; + if (tlist?.numberOfItems > 0) { + 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 +92,216 @@ 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) || + // 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) || (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); - } + attrs.forEach((attr) => { + changes[attr] = convertToNum(attr, selected.getAttribute(attr)) + }) } 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); + if (!initial) { + initial = mergeDeep({}, changes) + for (const [attr, val] of Object.entries(initial)) { + initial[attr] = convertToNum(attr, val) } } // save the start transform value too - initial.transform = context_.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; - let firstM; + const N = tlist.numberOfItems + let tx = 0; let ty = 0; let operation = 0 + + 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 +319,15 @@ export const recalculateDimensions = function (selected) { // } // } - const angle = getRotationAngle(child); - oldStartTransform = context_.getStartTransform(); + const angle = getRotationAngle(child) + oldStartTransform = svgCanvas.getStartTransform() // const childxforms = []; - context_.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,179 +339,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); - // childxforms.push(translateBack); - // childxforms.push(scale); - // childxforms.push(translateOrigin); - // logMatrix(translateBack.matrix); - // logMatrix(scale.matrix); + 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)); - // TODO: If any have this group as a parent and are - // referencing this child, then we need to impose a reverse - // scale 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; - // while (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) ); - // } - // } - context_.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 = context_.getStartTransform(); - context_.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)) } } - context_.setStartTransform(oldStartTransform); + svgCanvas.setStartTransform(oldStartTransform) } } } - context_.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 = context_.getStartTransform(); - context_.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)); - context_.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 @@ -523,130 +500,128 @@ 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 = context_.getStartTransform(); - context_.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)); - context_.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'); - if (fill && fill.startsWith('url(')) { - const paint = getRefElem(fill); - if (paint) { - 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); - } + + const fill = selected.getAttribute('fill') + if (fill?.startsWith('url(')) { + const paint = getRefElem(fill) + if (paint) { + 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) } } } @@ -660,92 +635,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 @@ -755,30 +730,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) } } } @@ -787,22 +762,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) } } } @@ -810,10 +785,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 b9bbd828..7b9951d2 100644 --- a/src/svgcanvas/sanitize.js +++ b/src/svgcanvas/sanitize.js @@ -6,11 +6,10 @@ * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller */ -import { getReverseNS, NS } from '../common/namespaces.js'; -import { isGecko } from '../common/browser.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 /** @@ -19,100 +18,102 @@ const REVERSE_NS = getReverseNS(); * @type {PlainObject} */ /* eslint-disable max-len */ -const svgGenericWhiteList = [ 'class', 'id', 'display', 'transform' ]; +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', 'style', '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', 'style', 'systemLanguage' ], - clipPath: [ 'clipPathUnits', 'id' ], + 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: [], - style: [ 'type' ], 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', 'style', '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', 'style', 'width', 'x', 'xlink:href', 'y' ], - foreignObject: [ 'font-size', 'height', 'opacity', 'requiredFeatures', 'style', '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', 'style', 'systemLanguage', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor' ], - image: [ 'clip-path', 'clip-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'style', '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', 'style', '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', 'systemLanguage', 'viewBox' ], - mask: [ 'height', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y' ], - metadata: [ 'id' ], - 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', 'style', 'systemLanguage' ], - pattern: [ 'height', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', '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', 'style', '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', 'style', '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', 'style', 'systemLanguage', 'width', 'x', 'y' ], - stop: [ 'offset', 'requiredFeatures', 'stop-opacity', 'style', 'systemLanguage', 'stop-color', 'gradientUnits', 'gradientTransform' ], - svg: [ 'clip-path', 'clip-rule', 'enable-background', 'filter', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', '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', 'style', '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', 'style', 'systemLanguage', 'text-anchor', 'x', 'xml:space', 'y' ], - textPath: [ 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', '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', 'r2', 'orient', 'cx', 'cy'], + 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', 'text-decoration', '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', 'style', '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', 'style', '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(([_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. @@ -121,143 +122,131 @@ Object.entries(svgWhiteList_).forEach(([ elt, atts ]) => { * @param {Text|Element} node - The DOM element to be checked (we'll also check its children) or text node to be cleaned up * @returns {void} */ -export const sanitizeSvg = function (node) { +export const sanitizeSvg = (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 (!({}.hasOwnProperty.call(allowedAttrsNS, attrLocalName) && - attrNsURI === allowedAttrsNS[attrLocalName] && attrNsURI !== NS.XMLNS - ) && - !(attrNsURI === NS.XMLNS && REVERSE_NS[attr.value])) { - // Bypassing the whitelist to allow se: prefixes. + 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('data-')) { - seAttrs.push([ attrName, attr.value ]); - } - console.warn(`sanitizeSvg: attribute ${attrName} in element ${node.nodeName} not in whitelist is removed`); - node.removeAttributeNS(attrNsURI, attrLocalName); - } - - // Add spaces before negative signs where necessary - if (isGecko()) { - switch (attrName) { - case 'transform': - case 'gradientTransform': - case 'patternTransform': { - const val = attr.value.replace(/(\d)-/g, '$1 -'); - // const val = attr.value.replace(/(?\d)-/g, '$ -'); - node.setAttribute(attrName, val); - break; - } + 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]) + } else { + 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 ]) => { - node.setAttributeNS(NS.SE, 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'], (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 3803b3c4..8b7f478b 100644 --- a/src/svgcanvas/select.js +++ b/src/svgcanvas/select.js @@ -6,14 +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 } from './utilities.js' +import { transformListToTransform, transformBox, transformPoint } from './math.js' -let svgFactory_; -let config_; -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. @@ -24,24 +23,24 @@ 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 = svgFactory_.createSVGElement({ + this.selectorGroup = svgCanvas.createSVGElement({ element: 'g', attr: { id: ('selectorGroup' + this.id) } - }); + }) // this holds a reference to the path rect - this.selectorRect = svgFactory_.createSVGElement({ + this.selectorRect = svgCanvas.createSVGElement({ element: 'path', attr: { id: ('selectedBox' + this.id), @@ -52,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 = { @@ -65,9 +64,9 @@ export class Selector { s: null, sw: null, w: null - }; + } - this.reset(this.selectedElement, bbox); + this.reset(this.selectedElement, bbox) } /** @@ -76,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') } /** @@ -88,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)) } } @@ -104,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 = svgFactory_.getDataStorage(); - const selectedBox = this.selectorRect; - const mgr = selectorManager_; - const selectedGrips = mgr.selectorGrips; - const selected = this.selectedElement; - const sw = selected.getAttribute('stroke-width'); - const currentZoom = svgFactory_.getCurrentZoom(); - let offset = 1 / currentZoom; + 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 / currentZoom; + 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 *= currentZoom; - m.f *= currentZoom; + 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 *= currentZoom; + offset *= zoom - const nbox = transformBox(l * currentZoom, t * currentZoom, w * currentZoom, h * currentZoom, 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 = svgFactory_.svgRoot().createSVGTransform(); - rot.setRotate(-angle, cx, cy); - const rotm = rot.matrix; - nbox.tl = transformPoint(nbox.tl.x, nbox.tl.y, rotm); - nbox.tr = transformPoint(nbox.tr.x, nbox.tr.y, rotm); - nbox.bl = transformPoint(nbox.bl.x, nbox.bl.y, rotm); - nbox.br = transformPoint(nbox.br.x, nbox.br.y, rotm); + 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'; - selectedBox.setAttribute('d', dstr); + ' ' + nbax + ',' + (nbay + nbah) + 'z' - const xform = angle ? 'rotate(' + [ angle, cx, cy ].join(',') + ')' : ''; - this.selectorGroup.setAttribute('transform', xform); + 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 ] - }; - 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)) // } } @@ -239,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')) + }) } } @@ -260,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 = { @@ -283,45 +282,45 @@ 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 = svgFactory_.getDataStorage(); + initGroup () { + const dataStorage = svgCanvas.getDataStorage() // remove old selector parent group if it existed - if (this.selectorParentGroup && this.selectorParentGroup.parentNode) { - this.selectorParentGroup.remove(); + if (this.selectorParentGroup?.parentNode) { + this.selectorParentGroup.remove() } // create parent selector group and add it to svgroot - this.selectorParentGroup = svgFactory_.createSVGElement({ + this.selectorParentGroup = svgCanvas.createSVGElement({ element: 'g', attr: { id: 'selectorParentGroup' } - }); - this.selectorGripsGroup = svgFactory_.createSVGElement({ + }) + this.selectorGripsGroup = svgCanvas.createSVGElement({ element: 'g', attr: { display: 'none' } - }); - this.selectorParentGroup.append(this.selectorGripsGroup); - svgFactory_.svgRoot().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) => { - const grip = svgFactory_.createSVGElement({ + const grip = svgCanvas.createSVGElement({ element: 'circle', attr: { id: ('selectorGrip_resize_' + dir), @@ -335,28 +334,28 @@ 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 = - svgFactory_.createSVGElement({ + svgCanvas.createSVGElement({ element: 'line', attr: { id: ('selectorGrip_rotateconnector'), stroke: '#22C', 'stroke-width': '1' } - }); - this.selectorGripsGroup.append(this.rotateGripConnector); + }) + this.selectorGripsGroup.append(this.rotateGripConnector) this.rotateGrip = - svgFactory_.createSVGElement({ + svgCanvas.createSVGElement({ element: 'circle', attr: { id: 'selectorGrip_rotate', @@ -364,16 +363,16 @@ export class SelectorManager { r: gripRadius, stroke: '#22C', 'stroke-width': 2, - style: `cursor:url(${config_.imgPath}/rotate.svg) 12 12, auto;` + 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 ] = config_.dimensions; - const canvasbg = svgFactory_.createSVGElement({ + const [width, height] = svgCanvas.curConfig.dimensions + const canvasbg = svgCanvas.createSVGElement({ element: 'svg', attr: { id: 'canvasBackground', @@ -384,9 +383,9 @@ export class SelectorManager { overflow: (isWebkit() ? 'none' : 'visible'), // Chrome 7 has a problem with this when zooming out style: 'pointer-events:none' } - }); + }) - const rect = svgFactory_.createSVGElement({ + const rect = svgCanvas.createSVGElement({ element: 'rect', attr: { width: '100%', @@ -398,14 +397,9 @@ export class SelectorManager { fill: '#FFF', style: 'pointer-events:none' } - }); - - // Both Firefox and WebKit are too slow with this filter region (especially at higher - // zoom levels) and Opera has at least one bug - // if (!isOpera()) rect.setAttribute('filter', 'url(#canvashadow)'); - canvasbg.append(rect); - svgFactory_.svgRoot().insertBefore(canvasbg, svgFactory_.svgContent()); - // Ok to replace above with `svgFactory_.svgContent().before(canvasbg);`? + }) + canvasbg.append(rect) + svgCanvas.getSvgRoot().insertBefore(canvasbg, svgCanvas.getSvgContent()) } /** @@ -414,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 (isNullish(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]; + if (!this.selectors[i]?.locked) { + this.selectors[i].locked = true + this.selectors[i].reset(elem, bbox) + this.selectorMap[elem.id] = this.selectors[i] + return this.selectors[i] } } // if we reached here, no available selectors were found, we create one - 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] } /** @@ -444,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]; - if (sel && !sel.locked) { + releaseSelector (elem) { + if (!elem) { return } + const N = this.selectors.length + const sel = this.selectorMap[elem.id] + if (!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 } } } @@ -473,10 +467,10 @@ 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 = - svgFactory_.createSVGElement({ + svgCanvas.createSVGElement({ element: 'rect', attr: { id: 'selectorRubberBand', @@ -487,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 } } @@ -501,7 +495,7 @@ export class SelectorManager { */ /** * @function module:select.SVGFactory#createSVGElement - * @param {module:utilities.EditorContext#addSVGElementFromJson} jsonMap + * @param {module:utilities.EditorContext#addSVGElementsFromJson} jsonMap * @returns {SVGElement} */ /** @@ -513,7 +507,7 @@ export class SelectorManager { * @returns {SVGSVGElement} */ /** - * @function module:select.SVGFactory#getCurrentZoom + * @function module:select.SVGFactory#getZoom * @returns {Float} The current zoom level */ @@ -536,14 +530,13 @@ export class SelectorManager { * @param {module:select.SVGFactory} svgFactory - An object implementing the SVGFactory interface. * @returns {void} */ -export const init = function (config, svgFactory) { - config_ = config; - svgFactory_ = svgFactory; - selectorManager_ = new SelectorManager(); -}; +export const init = (canvas) => { + 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 30ec70c2..b6c3c6d1 100644 --- a/src/svgcanvas/selected-elem.js +++ b/src/svgcanvas/selected-elem.js @@ -6,38 +6,51 @@ * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller */ -import { NS } from '../common/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, + getStrokedBBoxDefaultVisible, setHref, getElement, 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 elementContext_ = null; +let svgCanvas = null /** * @function module:selected-elem.init * @param {module:selected-elem.elementContext} elementContext * @returns {void} */ -export const init = function (elementContext) { - elementContext_ = elementContext; -}; +export const init = (canvas) => { + svgCanvas = canvas + svgCanvas.copySelectedElements = copySelectedElements + svgCanvas.groupSelectedElements = groupSelectedElements // Wraps all the selected elements in a group (`g`) element. + svgCanvas.pushGroupProperties = pushGroupProperty // Pushes all appropriate parent group properties down to its children + svgCanvas.ungroupSelectedElement = ungroupSelectedElement // Unwraps all the elements in a selected group (`g`) element + svgCanvas.moveToTopSelectedElement = moveToTopSelectedElem // Repositions the selected element to the bottom in the DOM to appear on top + svgCanvas.moveToBottomSelectedElement = moveToBottomSelectedElem // Repositions the selected element to the top in the DOM to appear under other elements + svgCanvas.moveUpDownSelected = moveUpDownSelected // Moves the select element up or down the stack, based on the visibly + svgCanvas.moveSelectedElements = moveSelectedElements // Moves selected elements on the X/Y axis. + svgCanvas.cloneSelectedElements = cloneSelectedElements // Create deep DOM copies (clones) of all selected elements and move them slightly + svgCanvas.alignSelectedElements = alignSelectedElements // Aligns selected elements. + svgCanvas.updateCanvas = updateCanvas // Updates the editor canvas width/height/position after a zoom has occurred. + svgCanvas.cycleElement = cycleElement // Select the next/previous element within the current layer. + svgCanvas.deleteSelectedElements = deleteSelectedElements // Removes all selected elements from the DOM and adds the change to the history +} /** * Repositions the selected element to the bottom in the DOM to appear on top of @@ -46,21 +59,21 @@ export const init = function (elementContext) { * @fires module:selected-elem.SvgCanvas#event:changed * @returns {void} */ -export const moveToTopSelectedElem = function () { - const [ selected ] = elementContext_.getSelectedElements(); - if (!isNullish(selected)) { - const t = selected; - const oldParent = t.parentNode; - const oldNextSibling = t.nextSibling; - t.parentNode.append(t); +const moveToTopSelectedElem = () => { + const [selected] = svgCanvas.getSelectedElements() + if (selected) { + 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) { - elementContext_.addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, 'top')); - elementContext_.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 @@ -69,30 +82,30 @@ export const moveToTopSelectedElem = function () { * @fires module:selected-elem.SvgCanvas#event:changed * @returns {void} */ -export const moveToBottomSelectedElem = function () { - const [ selected ] = elementContext_.getSelectedElements(); - if (!isNullish(selected)) { - let t = selected; - const oldParent = t.parentNode; - const oldNextSibling = t.nextSibling; - let { firstChild } = t.parentNode; +const moveToBottomSelectedElem = () => { + const [selected] = svgCanvas.getSelectedElements() + if (selected) { + 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) { - elementContext_.addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, 'bottom')); - elementContext_.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 @@ -102,45 +115,44 @@ export const moveToBottomSelectedElem = function () { * @fires module:selected-elem.SvgCanvas#event:changed * @returns {void} */ -export const moveUpDownSelected = function (dir) { - const selectedElements = elementContext_.getSelectedElements(); - const selected = selectedElements[0]; - if (!selected) { return; } +const moveUpDownSelected = (dir) => { + const selectedElements = svgCanvas.getSelectedElements() + const selected = selectedElements[0] + if (!selected) { return } - elementContext_.setCurBBoxes([]); - // curBBoxes = []; - let closest; let foundCur; + svgCanvas.setCurBBoxes([]) + let closest; let foundCur // jQuery sorts this list - const list = elementContext_.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) { + Array.prototype.forEach.call(list, (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) { - elementContext_.addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, 'Move ' + dir)); - elementContext_.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,54 +164,52 @@ export const moveUpDownSelected = function (dir) { * @returns {BatchCommand|void} Batch command for the move */ -export const moveSelectedElements = function (dx, dy, undoable = true) { - const selectedElements = elementContext_.getSelectedElements(); - const currentZoom = elementContext_.getCurrentZoom(); +const moveSelectedElements = (dx, dy, undoable = true) => { + 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 /= currentZoom; - dy /= currentZoom; + dx /= zoom + dy /= zoom } - const batchCmd = new BatchCommand('position'); - let i = selectedElements.length; - while (i--) { - const selected = selectedElements[i]; - if (!isNullish(selected)) { - const xform = elementContext_.getSVGRoot().createSVGTransform(); - const tlist = selected.transform?.baseVal; + const batchCmd = new BatchCommand('position') + selectedElements.forEach((selected, i) => { + if (selected) { + 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) } - elementContext_.gettingSelectorManager().requestSelector(selected).resize(); + svgCanvas.gettingSelectorManager().requestSelector(selected).resize() } - } + }) if (!batchCmd.isEmpty()) { if (undoable) { - elementContext_.addCommandToHistory(batchCmd); + svgCanvas.addCommandToHistory(batchCmd) } - elementContext_.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 @@ -209,21 +219,21 @@ export const moveSelectedElements = function (dx, dy, undoable = true) { * @param {Float} y Float with the distance to move on the y-axis * @returns {void} */ -export const cloneSelectedElements = function (x, y) { - const selectedElements = elementContext_.getSelectedElements(); - const currentGroup = elementContext_.getCurrentGroup(); - let i; let elem; - const batchCmd = new BatchCommand('Clone Elements'); +const cloneSelectedElements = (x, y) => { + 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; + const index = (el) => { + if (!el) return -1 + let i = 0 do { - i++; - } while (el == el.previousElementSibling); - return i; + i++ + } while (el === el.previousElementSibling) + return i } /** @@ -232,34 +242,34 @@ export const cloneSelectedElements = function (x, y) { * @param {Element} b * @returns {Integer} */ - function sortfunction(a, b) { - return (index(b) - index(a)); + const 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 (!elem) { break } } // use slice to quickly get the subset of elements we need - const copiedElements = selectedElements.slice(0, i); - elementContext_.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 = elementContext_.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()) { - elementContext_.addToSelection(copiedElements.reverse()); // Need to reverse for correct selection-adding - moveSelectedElements(x, y, false); - elementContext_.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 @@ -267,102 +277,102 @@ export const cloneSelectedElements = function (x, y) { * @param {"selected"|"largest"|"smallest"|"page"} relativeTo * @returns {void} */ -export const alignSelectedElements = function (type, relativeTo) { - const selectedElements = elementContext_.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 alignSelectedElements = (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 for (let i = 0; i < len; ++i) { - if (isNullish(selectedElements[i])) { break; } - const elem = selectedElements[i]; - bboxes[i] = getStrokedBBoxDefaultVisible([ elem ]); + if (!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 = elementContext_.getContentW(); - maxy = elementContext_.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 (!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 @@ -371,61 +381,61 @@ export const alignSelectedElements = function (type, relativeTo) { * @fires module:selected-elem.SvgCanvas#event:changed * @returns {void} */ -export const deleteSelectedElements = function () { - const selectedElements = elementContext_.getSelectedElements(); - const batchCmd = new BatchCommand('Delete Elements'); - const len = selectedElements.length; - const selectedCopy = []; // selectedElements is being deleted +const deleteSelectedElements = () => { + 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 (!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 - elementContext_.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)) } - elementContext_.getCanvas().setEmptySelectedElements(); + svgCanvas.setEmptySelectedElements() - if (!batchCmd.isEmpty()) { elementContext_.addCommandToHistory(batchCmd); } - elementContext_.call('changed', selectedCopy); - elementContext_.clearSelection(); -}; + if (!batchCmd.isEmpty()) { svgCanvas.addCommandToHistory(batchCmd) } + svgCanvas.call('changed', selectedCopy) + svgCanvas.clearSelection() +} /** * Remembers the current selected elements on the clipboard. * @function module:selected-elem.SvgCanvas#copySelectedElements * @returns {void} */ -export const copySelectedElements = function () { - const selectedElements = elementContext_.getSelectedElements(); +const copySelectedElements = () => { + const selectedElements = svgCanvas.getSelectedElements() const data = - JSON.stringify(selectedElements.map((x) => elementContext_.getJsonFromSvgElement(x))); + JSON.stringify(selectedElements.map((x) => svgCanvas.getJsonFromSvgElements(x))) // Use sessionStorage for the clipboard data. - sessionStorage.setItem(elementContext_.getClipboardID(), data); - elementContext_.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. @@ -434,58 +444,58 @@ export const copySelectedElements = function () { * @param {string} [urlArg] * @returns {void} */ -export const groupSelectedElements = function (type, urlArg) { - const selectedElements = elementContext_.getSelectedElements(); - if (!type) { type = 'g'; } - let cmdStr = ''; - let url; +const groupSelectedElements = (type, urlArg) => { + 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 = elementContext_.addSVGElementFromJson({ + const g = svgCanvas.addSVGElementsFromJson({ element: type, attr: { - id: elementContext_.getNextId() + 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 (!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()) { elementContext_.addCommandToHistory(batchCmd); } + if (!batchCmd.isEmpty()) { svgCanvas.addCommandToHistory(batchCmd) } // update selection - elementContext_.selectOnly([ g ], true); -}; + svgCanvas.selectOnly([g], true) +} /** * Pushes all appropriate parent group properties down to its children, then @@ -495,15 +505,15 @@ export const groupSelectedElements = function (type, urlArg) { * @param {boolean} undoable * @returns {BatchCommand|void} */ -export const pushGroupProperty = function (g, undoable) { - const children = g.childNodes; - const len = children.length; - const xform = g.getAttribute('transform'); +const pushGroupProperty = (g, undoable) => { + 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", @@ -512,77 +522,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 = elementContext_.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; - elementContext_.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 = elementContext_.getCanvas().getBlur(elem); - const origCblur = cblur; - if (!gblur) { gblur = elementContext_.getCanvas().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; - elementContext_.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) { - elementContext_.changeSelectedAttribute('stdDeviation', cblur, [ blurElem ]); - elementContext_.getCanvas().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 @@ -599,88 +609,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 = elementContext_.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 = elementContext_.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 = elementContext_.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 = elementContext_.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. @@ -689,154 +699,153 @@ export const pushGroupProperty = function (g, undoable) { * @fires module:selected-elem.SvgCanvas#event:selected * @returns {void} */ -export const convertToGroup = function (elem) { - const selectedElements = elementContext_.getSelectedElements(); +const convertToGroup = (elem) => { + const selectedElements = svgCanvas.getSelectedElements() if (!elem) { - elem = selectedElements[0]; + elem = selectedElements[0] } - const $elem = elem; - const batchCmd = new BatchCommand(); - let ts; - const dataStorage = elementContext_.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 = elementContext_.getSVGRoot().createSVGTransform(); - xform.setTranslate(pt.x, pt.y); - tlist.appendItem(xform); - recalculateDimensions(elem); - elementContext_.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 = elementContext_.getSVGContent(); - // const hasMore = svgcontent.querySelectorAll('use:data(symbol)').length; + 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 = elementContext_.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 - elementContext_.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 = elementContext_.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)) } - elementContext_.setUseData(g); + svgCanvas.setUseData(g) if (isGecko()) { - elementContext_.convertGradients(findDefs()); + svgCanvas.convertGradients(findDefs()) } else { - elementContext_.convertGradients(g); + svgCanvas.convertGradients(g) } // recalculate dimensions on the top-level children so that unnecessary transforms // are removed - walkTreePost(g, function (n) { + walkTreePost(g, (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(elementContext_.getVisElems()); - Array.prototype.forEach.call(visElems, function (el) { - if (!el.id) { el.id = elementContext_.getNextId(); } - }); + const visElems = g.querySelectorAll(svgCanvas.getVisElems()) + Array.prototype.forEach.call(visElems, (el) => { + if (!el.id) { el.id = svgCanvas.getNextId() } + }) - elementContext_.selectOnly([ g ]); + svgCanvas.selectOnly([g]) - const cm = pushGroupProperty(g, true); + const cm = pushGroupProperty(g, true) if (cm) { - batchCmd.addSubCommand(cm); + batchCmd.addSubCommand(cm) } - elementContext_.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 @@ -844,78 +853,73 @@ export const convertToGroup = function (elem) { * @function module:selected-elem.SvgCanvas#ungroupSelectedElement * @returns {void} */ -export const ungroupSelectedElement = function () { - const selectedElements = elementContext_.getSelectedElements(); - const dataStorage = elementContext_.getDataStorage(); - let g = selectedElements[0]; +const ungroupSelectedElement = () => { + 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 = getElement(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 } - if (anchor) { - anchor.before(elem); - } else { - g.after(elem); - } - children[i++] = elem; - 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 - elementContext_.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()) { elementContext_.addCommandToHistory(batchCmd); } + if (!batchCmd.isEmpty()) { svgCanvas.addCommandToHistory(batchCmd) } // update selection - elementContext_.addToSelection(children); + svgCanvas.addToSelection(children) } -}; +} /** * Updates the editor canvas width/height/position after a zoom has occurred. * @function module:svgcanvas.SvgCanvas#updateCanvas @@ -924,40 +928,40 @@ export const ungroupSelectedElement = function () { * @fires module:svgcanvas.SvgCanvas#event:ext_canvasUpdated * @returns {module:svgcanvas.CanvasInfo} */ -export const updateCanvas = function (w, h) { - elementContext_.getSVGRoot().setAttribute('width', w); - elementContext_.getSVGRoot().setAttribute('height', h); - const currentZoom = elementContext_.getCurrentZoom(); - const bg = document.getElementById('canvasBackground'); - const oldX = Number(elementContext_.getSVGContent().getAttribute('x')); - const oldY = Number(elementContext_.getSVGContent().getAttribute('y')); - const x = ((w - this.contentW * currentZoom) / 2); - const y = ((h - this.contentH * currentZoom) / 2); +const updateCanvas = (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 - svgCanvas.contentW * zoom) / 2) + const y = ((h - svgCanvas.contentH * zoom) / 2) - assignAttributes(elementContext_.getSVGContent(), { - width: this.contentW * currentZoom, - height: this.contentH * currentZoom, + assignAttributes(svgCanvas.getSvgContent(), { + width: svgCanvas.contentW * zoom, + height: svgCanvas.contentH * zoom, x, y, - viewBox: '0 0 ' + this.contentW + ' ' + this.contentH - }); + viewBox: '0 0 ' + svgCanvas.contentW + ' ' + svgCanvas.contentH + }) assignAttributes(bg, { - width: elementContext_.getSVGContent().getAttribute('width'), - height: elementContext_.getSVGContent().getAttribute('height'), + width: svgCanvas.getSvgContent().getAttribute('width'), + height: svgCanvas.getSvgContent().getAttribute('height'), x, y - }); + }) - const bgImg = getElem('background_image'); + const bgImg = getElement('background_image') if (bgImg) { assignAttributes(bgImg, { width: '100%', height: '100%' - }); + }) } - elementContext_.getCanvas().selectorManager.selectorParentGroup.setAttribute('transform', 'translate(' + x + ',' + y + ')'); + svgCanvas.selectorManager.selectorParentGroup.setAttribute('transform', 'translate(' + x + ',' + y + ')') /** * Invoked upon updates to the canvas. @@ -970,15 +974,15 @@ export const updateCanvas = function (w, h) { * @property {Integer} d_x * @property {Integer} d_y */ - elementContext_.getCanvas().runExtensions( + svgCanvas.runExtensions( 'canvasUpdated', /** * @type {module:svgcanvas.SvgCanvas#event:ext_canvasUpdated} */ { new_x: x, new_y: y, old_x: oldX, old_y: oldY, d_x: x - oldX, d_y: y - oldY } - ); - return { x, y, old_x: oldX, old_y: oldY, d_x: x - oldX, d_y: y - oldY }; -}; + ) + 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 @@ -986,32 +990,32 @@ export const updateCanvas = function (w, h) { * @fires module:svgcanvas.SvgCanvas#event:selected * @returns {void} */ -export const cycleElement = function (next) { - const selectedElements = elementContext_.getSelectedElements(); - const currentGroup = elementContext_.getCurrentGroup(); - let num; - const curElem = selectedElements[0]; - let elem = false; - const allElems = getVisibleElements(currentGroup || elementContext_.getCanvas().getCurrentDrawing().getCurrentLayer()); - if (!allElems.length) { return; } - if (isNullish(curElem)) { - num = next ? allElems.length - 1 : 0; - elem = allElems[num]; +const cycleElement = (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 } + if (!curElem) { + 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 } } } - elementContext_.getCanvas().selectOnly([ elem ], true); - elementContext_.call('selected', selectedElements); -}; + svgCanvas.selectOnly([elem], true) + svgCanvas.call('selected', selectedElements) +} diff --git a/src/svgcanvas/selection.js b/src/svgcanvas/selection.js index 40e71bf6..744d9585 100644 --- a/src/svgcanvas/selection.js +++ b/src/svgcanvas/selection.js @@ -5,417 +5,457 @@ * @copyright 2011 Jeff Schiller */ -import { NS } from '../common/namespaces.js'; +import { NS } from './namespaces.js' import { - isNullish, getBBox as utilsGetBBox, getStrokedBBoxDefaultVisible -} from './utilities.js'; -import { transformPoint, transformListToTransform, rectsIntersect } from './math.js'; -import * as hstry from './history.js'; -import { getClosest } from '../editor/components/jgraduate/Util.js'; + getBBox, + getStrokedBBoxDefaultVisible +} from './utilities.js' +import { + transformPoint, + transformListToTransform, + rectsIntersect +} from './math.js' +import * as hstry from './history.js' +import { getClosest } from '../editor/components/jgraduate/Util.js' -const { BatchCommand } = hstry; -let selectionContext_ = null; -let svgCanvas = null; -let selectedElements; +const { BatchCommand } = hstry +let svgCanvas = null /** -* @function module:selection.init -* @param {module:selection.selectionContext} selectionContext -* @returns {void} -*/ -export const init = function (selectionContext) { - selectionContext_ = selectionContext; - svgCanvas = selectionContext_.getCanvas(); - selectedElements = selectionContext_.getSelectedElements; -}; + * @function module:selection.init + * @param {module:selection.selectionContext} selectionContext + * @returns {void} + */ +export const init = (canvas) => { + svgCanvas = canvas +} /** -* Clears the selection. The 'selected' handler is then optionally called. -* This should really be an intersection applying to all types rather than a union. -* @name module:selection.SvgCanvas#clearSelection -* @type {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection} -* @fires module:selection.SvgCanvas#event:selected -*/ -export const clearSelectionMethod = function (noCall) { - selectedElements().forEach((elem) => { - if (isNullish(elem)) { - return; + * Clears the selection. The 'selected' handler is then optionally called. + * This should really be an intersection applying to all types rather than a union. + * @name module:selection.SvgCanvas#clearSelection + * @type {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection} + * @fires module:selection.SvgCanvas#event:selected + */ +export const clearSelectionMethod = (noCall) => { + const selectedElements = svgCanvas.getSelectedElements() + selectedElements.forEach((elem) => { + if (!elem) { + return } - svgCanvas.selectorManager.releaseSelector(elem); - }); - svgCanvas.setEmptySelectedElements(); - if (!noCall) { svgCanvas.call('selected', selectedElements()); } -}; + svgCanvas.selectorManager.releaseSelector(elem) + }) + svgCanvas?.setEmptySelectedElements() + + if (!noCall) { + svgCanvas.call('selected', svgCanvas.getSelectedElements()) + } +} /** -* Adds a list of elements to the selection. The 'selected' handler is then called. -* @name module:selection.SvgCanvas#addToSelection -* @type {module:path.EditorContext#addToSelection} -* @fires module:selection.SvgCanvas#event:selected -*/ -export const addToSelectionMethod = function (elemsToAdd, showGrips) { - if (!elemsToAdd.length) { return; } + * Adds a list of elements to the selection. The 'selected' handler is then called. + * @name module:selection.SvgCanvas#addToSelection + * @type {module:path.EditorContext#addToSelection} + * @fires module:selection.SvgCanvas#event:selected + */ +export const addToSelectionMethod = (elemsToAdd, showGrips) => { + const selectedElements = svgCanvas.getSelectedElements() + if (!elemsToAdd.length) { + return + } // find the first null in our selectedElements array - let j = 0; - while (j < selectedElements().length) { - if (isNullish(selectedElements()[j])) { - break; + let firstNull = 0 + while (firstNull < selectedElements.length) { + if (selectedElements[firstNull] === null) { + break } - ++j; + ++firstNull } // now add each element consecutively - let i = elemsToAdd.length; + let i = elemsToAdd.length while (i--) { - let elem = elemsToAdd[i]; - if (!elem) { continue; } - const bbox = utilsGetBBox(elem); - if (!bbox) { continue; } + let elem = elemsToAdd[i] + if (!elem || !elem.getBBox) { + continue + } 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()[j] = elem; + if (!selectedElements.includes(elem)) { + selectedElements[firstNull] = elem // only the first selectedBBoxes element is ever used in the codebase these days // if (j === 0) selectedBBoxes[0] = utilsGetBBox(elem); - j++; - const sel = svgCanvas.selectorManager.requestSelector(elem, bbox); + firstNull++ + const sel = svgCanvas.selectorManager.requestSelector(elem) - if (selectedElements().length > 1) { - sel.showGrips(false); + if (selectedElements.length > 1) { + sel.showGrips(false) } } } - if (!selectedElements().length) { - return; + if (!selectedElements.length) { + return } - svgCanvas.call('selected', selectedElements()); + svgCanvas.call('selected', selectedElements) - if (selectedElements().length === 1) { - svgCanvas.selectorManager.requestSelector(selectedElements()[0]).showGrips(showGrips); + if (selectedElements.length === 1) { + svgCanvas.selectorManager + .requestSelector(selectedElements[0]) + .showGrips(showGrips) } // make sure the elements are in the correct order // See: https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition - selectedElements().sort(function (a, b) { + selectedElements.sort((a, b) => { if (a && b && a.compareDocumentPosition) { - return 3 - (b.compareDocumentPosition(a) & 6); // eslint-disable-line no-bitwise + return 3 - (b.compareDocumentPosition(a) & 6) } - if (isNullish(a)) { - return 1; + if (!a) { + return 1 } - return 0; - }); + return 0 + }) // Make sure first elements are not null - while (isNullish(selectedElements())[0]) { - selectedElements().shift(0); + while (!selectedElements[0]) { + selectedElements.shift(0) } -}; +} /** -* @name module:svgcanvas.SvgCanvas#getMouseTarget -* @type {module:path.EditorContext#getMouseTarget} -*/ -export const getMouseTargetMethod = function (evt) { - if (isNullish(evt)) { - return null; + * @name module:svgcanvas.SvgCanvas#getMouseTarget + * @type {module:path.EditorContext#getMouseTarget} + */ +export const getMouseTargetMethod = (evt) => { + if (!evt) { + 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; } + if (mouseTarget.correspondingUseElement) { + mouseTarget = mouseTarget.correspondingUseElement + } // for foreign content, go up until we find the foreignObject // WebKit browsers set the mouse target to the svgcanvas div - if ([ NS.MATH, NS.HTML ].includes(mouseTarget.namespaceURI) && + if ( + [NS.MATH, NS.HTML].includes(mouseTarget.namespaceURI) && mouseTarget.id !== 'svgcanvas' ) { while (mouseTarget.nodeName !== 'foreignObject') { - mouseTarget = mouseTarget.parentNode; - if (!mouseTarget) { return selectionContext_.getSVGRoot(); } + mouseTarget = mouseTarget.parentNode + if (!mouseTarget) { + 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 = selectionContext_.getSVGRoot(); - const container = selectionContext_.getDOMContainer(); - const content = selectionContext_.getSVGContent(); - if ([ svgRoot, container, content, currentLayer ].includes(mouseTarget)) { - return selectionContext_.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')) { // 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 (!mouseTarget?.parentNode?.isSameNode(selectionContext_.getCurrentGroup() || currentLayer)) { - mouseTarget = mouseTarget.parentNode; + while ( + !mouseTarget?.parentNode?.isSameNode( + svgCanvas.getCurrentGroup() || currentLayer + ) + ) { + 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 -*/ + * @typedef {module:svgcanvas.ExtensionMouseDownStatus|module:svgcanvas.ExtensionMouseUpStatus|module:svgcanvas.ExtensionIDsUpdatedStatus|module:locale.ExtensionLocaleData[]|void} module:svgcanvas.ExtensionStatus + * @tutorial ExtensionDocs + */ /** -* @callback module:svgcanvas.ExtensionVarBuilder -* @param {string} name The name of the extension -* @returns {module:svgcanvas.SvgCanvas#event:ext_addLangData} -*/ + * @callback module:svgcanvas.ExtensionVarBuilder + * @param {string} name The name of the extension + * @returns {module:svgcanvas.SvgCanvas#event:ext_addLangData} + */ /** -* @callback module:svgcanvas.ExtensionNameFilter -* @param {string} name -* @returns {boolean} -*/ + * @callback module:svgcanvas.ExtensionNameFilter + * @param {string} name + * @returns {boolean} + */ /* eslint-disable max-len */ /** -* @todo Consider: Should this return an array by default, so extension results aren't overwritten? -* @todo Would be easier to document if passing in object with key of action and vars as value; could then define an interface which tied both together -* @function module:svgcanvas.SvgCanvas#runExtensions -* @param {"mouseDown"|"mouseMove"|"mouseUp"|"zoomChanged"|"IDsUpdated"|"canvasUpdated"|"toolButtonStateUpdate"|"selectedChanged"|"elementTransition"|"elementChanged"|"langReady"|"langChanged"|"addLangData"|"onNewDocument"|"workareaResized"} action -* @param {module:svgcanvas.SvgCanvas#event:ext_mouseDown|module:svgcanvas.SvgCanvas#event:ext_mouseMove|module:svgcanvas.SvgCanvas#event:ext_mouseUp|module:svgcanvas.SvgCanvas#event:ext_zoomChanged|module:svgcanvas.SvgCanvas#event:ext_IDsUpdated|module:svgcanvas.SvgCanvas#event:ext_canvasUpdated|module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate|module:svgcanvas.SvgCanvas#event:ext_selectedChanged|module:svgcanvas.SvgCanvas#event:ext_elementTransition|module:svgcanvas.SvgCanvas#event:ext_elementChanged|module:svgcanvas.SvgCanvas#event:ext_langReady|module:svgcanvas.SvgCanvas#event:ext_langChanged|module:svgcanvas.SvgCanvas#event:ext_addLangData|module:svgcanvas.SvgCanvas#event:ext_onNewDocument|module:svgcanvas.SvgCanvas#event:ext_workareaResized|module:svgcanvas.ExtensionVarBuilder} [vars] -* @param {boolean} [returnArray] -* @param {module:svgcanvas.ExtensionNameFilter} nameFilter -* @returns {GenericArray|module:svgcanvas.ExtensionStatus|false} See {@tutorial ExtensionDocs} on the ExtensionStatus. -*/ + * @todo Consider: Should this return an array by default, so extension results aren't overwritten? + * @todo Would be easier to document if passing in object with key of action and vars as value; could then define an interface which tied both together + * @function module:svgcanvas.SvgCanvas#runExtensions + * @param {"mouseDown"|"mouseMove"|"mouseUp"|"zoomChanged"|"IDsUpdated"|"canvasUpdated"|"toolButtonStateUpdate"|"selectedChanged"|"elementTransition"|"elementChanged"|"langReady"|"langChanged"|"addLangData"|"onNewDocument"|"workareaResized"} action + * @param {module:svgcanvas.SvgCanvas#event:ext_mouseDown|module:svgcanvas.SvgCanvas#event:ext_mouseMove|module:svgcanvas.SvgCanvas#event:ext_mouseUp|module:svgcanvas.SvgCanvas#event:ext_zoomChanged|module:svgcanvas.SvgCanvas#event:ext_IDsUpdated|module:svgcanvas.SvgCanvas#event:ext_canvasUpdated|module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate|module:svgcanvas.SvgCanvas#event:ext_selectedChanged|module:svgcanvas.SvgCanvas#event:ext_elementTransition|module:svgcanvas.SvgCanvas#event:ext_elementChanged|module:svgcanvas.SvgCanvas#event:ext_langReady|module:svgcanvas.SvgCanvas#event:ext_langChanged|module:svgcanvas.SvgCanvas#event:ext_addLangData|module:svgcanvas.SvgCanvas#event:ext_onNewDocument|module:svgcanvas.SvgCanvas#event:ext_workareaResized|module:svgcanvas.ExtensionVarBuilder} [vars] + * @param {boolean} [returnArray] + * @param {module:svgcanvas.ExtensionNameFilter} nameFilter + * @returns {GenericArray|module:svgcanvas.ExtensionStatus|false} See {@tutorial ExtensionDocs} on the ExtensionStatus. + */ /* eslint-enable max-len */ -export const runExtensionsMethod = function (action, vars, returnArray, nameFilter) { - let result = returnArray ? [] : false; - for (const [ name, ext ] of Object.entries(selectionContext_.getExtensions())) { +export const runExtensionsMethod = ( + action, + vars, + returnArray, + nameFilter +) => { + 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 + 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). -* Note that 0-opacity, off-screen etc elements are still considered "visible" -* for this function. -* @function module:svgcanvas.SvgCanvas#getVisibleElementsAndBBoxes -* @param {Element} parent - The parent DOM element to search within -* @returns {ElementAndBBox[]} An array with objects that include: -*/ -export const getVisibleElementsAndBBoxes = function (parent) { + * Get all elements that have a BBox (excludes ``, ``, etc). + * Note that 0-opacity, off-screen etc elements are still considered "visible" + * for this function. + * @function module:svgcanvas.SvgCanvas#getVisibleElementsAndBBoxes + * @param {Element} parent - The parent DOM element to search within + * @returns {ElementAndBBox[]} An array with objects that include: + */ +export const getVisibleElementsAndBBoxes = (parent) => { if (!parent) { - const svgcontent = selectionContext_.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; - Array.prototype.forEach.call(elements, function (elem) { + 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 -* intersect the multi-select rubber-band-box on the currentLayer only. -* -* We brute-force `getIntersectionList` for browsers that do not support it (Firefox). -* -* Reference: -* Firefox does not implement `getIntersectionList()`, see {@link https://bugzilla.mozilla.org/show_bug.cgi?id=501421}. -* @function module:svgcanvas.SvgCanvas#getIntersectionList -* @param {SVGRect} rect -* @returns {Element[]|NodeList} Bbox elements -*/ -export const getIntersectionListMethod = function (rect) { - const currentZoom = selectionContext_.getCurrentZoom(); - if (isNullish(selectionContext_.getRubberBox())) { return null; } - - const parent = selectionContext_.getCurrentGroup() || svgCanvas.getCurrentDrawing().getCurrentLayer(); - - let rubberBBox; - if (!rect) { - rubberBBox = selectionContext_.getRubberBox().getBBox(); - const bb = selectionContext_.getSVGContent().createSVGRect(); - - [ 'x', 'y', 'width', 'height', 'top', 'right', 'bottom', 'left' ].forEach((o) => { - bb[o] = rubberBBox[o] / currentZoom; - }); - rubberBBox = bb; - } else { - rubberBBox = selectionContext_.getSVGContent().createSVGRect(); - rubberBBox.x = rect.x; - rubberBBox.y = rect.y; - rubberBBox.width = rect.width; - rubberBBox.height = rect.height; + * This method sends back an array or a NodeList full of elements that + * intersect the multi-select rubber-band-box on the currentLayer only. + * + * We brute-force `getIntersectionList` for browsers that do not support it (Firefox). + * + * Reference: + * Firefox does not implement `getIntersectionList()`, see {@link https://bugzilla.mozilla.org/show_bug.cgi?id=501421}. + * @function module:svgcanvas.SvgCanvas#getIntersectionList + * @param {SVGRect} rect + * @returns {Element[]|NodeList} Bbox elements + */ +export const getIntersectionListMethod = (rect) => { + const zoom = svgCanvas.getZoom() + if (!svgCanvas.getRubberBox()) { + return null } - let resultList = null; + const parent = + svgCanvas.getCurrentGroup() || + svgCanvas.getCurrentDrawing().getCurrentLayer() - if (isNullish(resultList) || typeof resultList.item !== 'function') { - resultList = []; + let rubberBBox + if (!rect) { + rubberBBox = getBBox(svgCanvas.getRubberBox()) + const bb = svgCanvas.getSvgContent().createSVGRect(); - if (!selectionContext_.getCurBBoxes().length) { - // Cache all bboxes - selectionContext_.setCurBBoxes(getVisibleElementsAndBBoxes(parent)); - } - let i = selectionContext_.getCurBBoxes().length; - while (i--) { - const curBBoxes = selectionContext_.getCurBBoxes(); - if (!rubberBBox.width) { continue; } - if (rectsIntersect(rubberBBox, curBBoxes[i].bbox)) { - resultList.push(curBBoxes[i].elem); + ['x', 'y', 'width', 'height', 'top', 'right', 'bottom', 'left'].forEach( + (o) => { + bb[o] = rubberBBox[o] / zoom } + ) + rubberBBox = bb + } else { + rubberBBox = svgCanvas.getSvgContent().createSVGRect() + rubberBBox.x = rect.x + rubberBBox.y = rect.y + rubberBBox.width = rect.width + rubberBBox.height = rect.height + } + + const resultList = [] + if (svgCanvas.getCurBBoxes().length === 0) { + // Cache all bboxes + svgCanvas.setCurBBoxes(getVisibleElementsAndBBoxes(parent)) + } + let i = svgCanvas.getCurBBoxes().length + while (i--) { + const curBBoxes = svgCanvas.getCurBBoxes() + if (!rubberBBox.width) { + continue + } + if (rectsIntersect(rubberBBox, curBBoxes[i].bbox)) { + resultList.push(curBBoxes[i].elem) } } // addToSelection expects an array, but it's ok to pass a NodeList // because using square-bracket notation is allowed: // https://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html - return resultList; -}; + return resultList +} /** -* @typedef {PlainObject} ElementAndBBox -* @property {Element} elem - The element -* @property {module:utilities.BBoxObject} bbox - The element's BBox as retrieved from `getStrokedBBoxDefaultVisible` -*/ + * @typedef {PlainObject} ElementAndBBox + * @property {Element} elem - The element + * @property {module:utilities.BBoxObject} bbox - The element's BBox as retrieved from `getStrokedBBoxDefaultVisible` + */ /** -* Wrap an SVG element into a group element, mark the group as 'gsvg'. -* @function module:svgcanvas.SvgCanvas#groupSvgElem -* @param {Element} elem - SVG element to wrap -* @returns {void} -*/ -export const groupSvgElem = function (elem) { - const dataStorage = selectionContext_.getDataStorage(); - const g = document.createElementNS(NS.SVG, 'g'); - elem.replaceWith(g); - g.appendChild(elem); - dataStorage.put(g, 'gsvg', elem); - g.id = svgCanvas.getNextId(); -}; + * Wrap an SVG element into a group element, mark the group as 'gsvg'. + * @function module:svgcanvas.SvgCanvas#groupSvgElem + * @param {Element} elem - SVG element to wrap + * @returns {void} + */ +export const groupSvgElem = (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() +} /** -* Runs the SVG Document through the sanitizer and then updates its paths. -* @function module:svgcanvas.SvgCanvas#prepareSvg -* @param {XMLDocument} newDoc - The SVG DOM document -* @returns {void} -*/ -export const prepareSvg = function (newDoc) { - svgCanvas.sanitizeSvg(newDoc.documentElement); + * Runs the SVG Document through the sanitizer and then updates its paths. + * @function module:svgcanvas.SvgCanvas#prepareSvg + * @param {XMLDocument} newDoc - The SVG DOM document + * @returns {void} + */ +export const prepareSvg = (newDoc) => { + 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) => { - path.setAttribute('d', svgCanvas.pathActions.convertPath(path)); - 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 -* transformed center. -* @function module:svgcanvas.SvgCanvas#setRotationAngle -* @param {string|Float} val - The new rotation angle in degrees -* @param {boolean} preventUndo - Indicates whether the action should be undoable or not -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ -export const setRotationAngle = function (val, preventUndo) { + * Removes any old rotations if present, prepends a new rotation at the + * transformed center. + * @function module:svgcanvas.SvgCanvas#setRotationAngle + * @param {string|Float} val - The new rotation angle in degrees + * @param {boolean} preventUndo - Indicates whether the action should be undoable or not + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ +export const setRotationAngle = (val, preventUndo) => { + 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 = utilsGetBBox(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 if (val !== 0) { - const center = transformPoint(cx, cy, transformListToTransform(tlist).matrix); - const Rnc = selectionContext_.getSVGRoot().createSVGTransform(); - Rnc.setRotate(val, center.x, center.y); + const center = transformPoint( + cx, + cy, + transformListToTransform(tlist).matrix + ) + 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', newTransform, selectedElements()); - svgCanvas.call('changed', selectedElements()); + svgCanvas.changeSelectedAttribute( + 'transform', + newTransform, + selectedElements + ) + svgCanvas.call('changed', selectedElements) } - // const pointGripContainer = getElem('pathpointgrip_container'); + // const pointGripContainer = getElement('pathpointgrip_container'); // if (elem.nodeName === 'path' && pointGripContainer) { // pathActions.setPointContainerTransform(elem.getAttribute('transform')); // } - const selector = svgCanvas.selectorManager.requestSelector(selectedElements()[0]); - selector.resize(); - selectionContext_.getSelector().updateGripCursors(val); -}; + const selector = svgCanvas.selectorManager.requestSelector( + selectedElements[0] + ) + selector.resize() + svgCanvas.getSelector().updateGripCursors(val) +} /** -* Runs `recalculateDimensions` on the selected elements, -* adding the changes to a single batch command. -* @function module:svgcanvas.SvgCanvas#recalculateAllSelectedDimensions -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ -export const recalculateAllSelectedDimensions = function () { - const text = (selectionContext_.getCurrentResizeMode() === 'none' ? 'position' : 'size'); - const batchCmd = new BatchCommand(text); + * Runs `recalculateDimensions` on the selected elements, + * adding the changes to a single batch command. + * @function module:svgcanvas.SvgCanvas#recalculateAllSelectedDimensions + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ +export const recalculateAllSelectedDimensions = () => { + const text = + svgCanvas.getCurrentResizeMode() === 'none' ? 'position' : 'size' + const batchCmd = new BatchCommand(text) + const selectedElements = svgCanvas.getSelectedElements() - let i = selectedElements().length; - while (i--) { - const elem = selectedElements()[i]; - const cmd = svgCanvas.recalculateDimensions(elem); + selectedElements.forEach((elem) => { + const cmd = svgCanvas.recalculateDimensions(elem) if (cmd) { - batchCmd.addSubCommand(cmd); + batchCmd.addSubCommand(cmd) } - } + }) if (!batchCmd.isEmpty()) { - selectionContext_.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 97ba5a1a..8901d5bf 100644 --- a/src/svgcanvas/svg-exec.js +++ b/src/svgcanvas/svg-exec.js @@ -5,103 +5,101 @@ * @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 '../common/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 svgContext_ = null; -let svgCanvas = null; +let svgCanvas = null /** * @function module:svg-exec.init * @param {module:svg-exec.SvgCanvas#init} svgContext * @returns {void} */ -export const init = function (svgContext) { - svgContext_ = svgContext; - svgCanvas = svgContext_.getCanvas(); -}; +export const init = (canvas) => { + svgCanvas = canvas +} /** * Main function to set up the SVG content for output. * @function module:svgcanvas.SvgCanvas#svgCanvasToString * @returns {string} The SVG image for output */ -export const svgCanvasToString = function () { +export const svgCanvasToString = () => { // 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 = svgContext_.getSVGContent().childNodes; + const childNodesElems = svgCanvas.getSvgContent().childNodes childNodesElems.forEach(function (node, i) { if (i && node.nodeType === 8 && node.data.includes('Created with')) { - svgContext_.getSVGContent().firstChild.before(node); + svgCanvas.getSvgContent().firstChild.before(node) } - }); + }) // Move out of in-group editing mode - if (svgContext_.getCurrentGroup()) { - draw.leaveContext(); - svgCanvas.selectOnly([ svgContext_.getCurrentGroup() ]); + if (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 = svgContext_.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(svgContext_.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. @@ -111,27 +109,27 @@ export const svgCanvasToString = function () { * @returns {string} The given element as an SVG tag */ export const svgToString = function (elem, indent) { - const curConfig = svgContext_.getCurConfig(); - const nsMap = svgContext_.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') { @@ -145,146 +143,146 @@ 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 - if (svgContext_.getSvgOptionApply() && + if (svgCanvas.getSvgOptionApply() && elem.nodeName === 'image' && attr.localName === 'href' && - svgContext_.getSvgOptionImages() && - svgContext_.getSvgOptionImages() === 'embed' + svgCanvas.getSvgOptionImages() && + svgCanvas.getSvgOptionImages() === 'embed' ) { - const img = svgContext_.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. @@ -300,209 +298,208 @@ export const svgToString = function (elem, indent) { * unsuccessful, `true` otherwise. */ export const setSvgString = function (xmlString, preventUndo) { - const curConfig = svgContext_.getCurConfig(); - const dataStorage = svgContext_.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 } = svgContext_.getSVGContent(); + const { nextSibling } = svgCanvas.getSvgContent() - svgContext_.getSVGContent().remove(); - const oldzoom = svgContext_.getSVGContent(); - batchCmd.addSubCommand(new RemoveElementCommand(oldzoom, nextSibling, svgContext_.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 (svgContext_.getDOMDocument().adoptNode) { - svgContext_.setSVGContent(svgContext_.getDOMDocument().adoptNode(newDoc.documentElement)); + if (svgCanvas.getDOMDocument().adoptNode) { + svgCanvas.setSvgContent(svgCanvas.getDOMDocument().adoptNode(newDoc.documentElement)) } else { - svgContext_.setSVGContent(svgContext_.getDOMDocument().importNode(newDoc.documentElement, true)); + svgCanvas.setSvgContent(svgCanvas.getDOMDocument().importNode(newDoc.documentElement, true)) } - svgContext_.getSVGRoot().append(svgContext_.getSVGContent()); - const content = svgContext_.getSVGContent(); + svgCanvas.getSvgRoot().append(svgCanvas.getSvgContent()) + const content = svgCanvas.getSvgContent() - svgCanvas.current_drawing_ = new draw.Drawing(svgContext_.getSVGContent(), svgContext_.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) { - svgContext_.call('setnonce', nonce); + svgCanvas.call('setnonce', nonce) } else { - svgContext_.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(svgContext_.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(svgContext_.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(svgContext_.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 - svgContext_.setCurrentZoom(1); + svgCanvas.setZoom(1) - svgCanvas.clearSelection(); - pathModule.clearData(); - svgContext_.getSVGRoot().append(svgCanvas.selectorManager.selectorParentGroup); + svgCanvas.clearSelection() + pathModule.clearData() + svgCanvas.getSvgRoot().append(svgCanvas.selectorManager.selectorParentGroup) - if (!preventUndo) svgContext_.addCommandToHistory(batchCmd); - svgContext_.call('changed', [ svgContext_.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 @@ -519,120 +516,120 @@ export const setSvgString = function (xmlString, preventUndo) { * was obtained */ export const importSvgString = function (xmlString) { - const dataStorage = svgContext_.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 (svgContext_.getImportIds(uid) && svgContext_.getImportIds(uid).symbol) { - const parents = getParents(svgContext_.getImportIds(uid).symbol, '#svgroot'); - if (parents.length) { - useExisting = true; + if (svgCanvas.getImportIds(uid) && svgCanvas.getImportIds(uid).symbol) { + const parents = getParents(svgCanvas.getImportIds(uid).symbol, '#svgroot') + if (parents?.length) { + useExisting = true } } - const batchCmd = new BatchCommand('Import Image'); - let symbol; + const batchCmd = new BatchCommand('Import Image') + let symbol if (useExisting) { - symbol = svgContext_.getImportIds(uid).symbol; - ts = svgContext_.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 = svgContext_.getDOMDocument().adoptNode - ? svgContext_.getDOMDocument().adoptNode(newDoc.documentElement) - : svgContext_.getDOMDocument().importNode(newDoc.documentElement, true); + const svg = svgCanvas.getDOMDocument().adoptNode + ? svgCanvas.getDOMDocument().adoptNode(newDoc.documentElement) + : 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(svgContext_.getSVGContent().getAttribute('height')); + const // canvasw = +svgContent.getAttribute('width'), + 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 = svgContext_.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 - svgContext_.setImportIds(uid, { + svgCanvas.setImportIds(uid, { symbol, xform: ts - }); + }) - findDefs().append(symbol); - batchCmd.addSubCommand(new InsertElementCommand(symbol)); + findDefs().append(symbol) + batchCmd.addSubCommand(new InsertElementCommand(symbol)) } - useEl = svgContext_.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); - (svgContext_.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; // } - svgContext_.addCommandToHistory(batchCmd); - svgContext_.call('changed', [ svgContext_.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 @@ -649,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'); - svgContext_.setEncodableImages(src, urldata); + let urldata = ';svgedit_url=' + encodeURIComponent(src) + urldata = cvs.toDataURL().replace(';base64', urldata + ';base64') + svgCanvas.setEncodableImages(src, urldata) } catch (e) { - svgContext_.setEncodableImages(src, false); + svgCanvas.setEncodableImages(src, false) } - svgCanvas.setGoodImage(src); - resolve(svgContext_.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 @@ -685,35 +682,35 @@ export const embedImage = function (src) { * Codes only is useful for locale-independent detection. * @returns {module:svgcanvas.IssuesAndCodes} */ -function getIssues() { - const uiStrings = svgContext_.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 = svgContext_.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 @@ -743,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 = svgContext_.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) { - svgContext_.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 @@ -827,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 = svgContext_.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); - svgContext_.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 @@ -869,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. // @@ -878,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 @@ -888,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 - svgContext_.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. @@ -963,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 = svgContext_.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.getElement(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, @@ -990,53 +994,53 @@ export const setUseDataMethod = function (parent) { * @returns {Integer} The number of elements that were removed */ export const removeUnusedDefElemsMethod = function () { - const defs = svgContext_.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 = svgContext_.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) - svgContext_.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 @@ -1044,55 +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 = svgContext_.getSVGContent(); + const svgContent = svgCanvas.getSvgContent() // TODO: Support more than one element with this ref by duplicating parent grad - const fillStrokeElems = svgcontent.querySelectorAll('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]'); - if (!fillStrokeElems.length) { return; } - + let fillStrokeElems = svgContent.querySelectorAll('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]') + if (!fillStrokeElems.length) { + const tmpFillStrokeElems = svgContent.querySelectorAll('[*|href="#' + grad.id + '"]') + if (!tmpFillStrokeElems.length) { + 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 + ')"]') + } else { + 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; - 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 tlist = grad.gradientTransform.baseVal + if (tlist?.numberOfItems > 0) { + const m = transformListToTransform(tlist).matrix + const pt1 = transformPoint(gCoords.x1, gCoords.y1, m) + const pt2 = transformPoint(gCoords.x2, gCoords.y2, m) - gCoords.x1 = pt1.x; - gCoords.y1 = pt1.y; - gCoords.x2 = pt2.x; - gCoords.y2 = pt2.y; - grad.removeAttribute('gradientTransform'); + 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 5549a060..599814ca 100644 --- a/src/svgcanvas/svgcanvas.js +++ b/src/svgcanvas/svgcanvas.js @@ -4,2773 +4,962 @@ * * @license MIT * - * @copyright 2010 Alexis Deveria, 2010 Pavol Rusnak, 2010 Jeff Schiller + * @copyright 2010 Alexis Deveria, 2010 Pavol Rusnak, 2010 Jeff Schiller, 2021 OptimistikSAS * */ -import { Canvg as canvg } from 'canvg'; -import '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 hstry 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'; - -// eslint-disable-next-line no-duplicate-imports +} from './paste-elem.js' +import { svgRootElement } from './svgroot.js' import { - identifyLayers, createLayer, cloneLayer, deleteCurrentLayer, - setCurrentLayer, renameCurrentLayer, setCurrentLayerPosition, - setLayerVisibility, moveSelectedToLayer, mergeLayer, mergeAllLayers, - leaveContext, setContext -} from './draw.js'; -import { svgRootElement } from './svgroot.js'; -import { - init as undoInit, getUndoManager, changeSelectedAttributeNoUndoMethod, - changeSelectedAttributeMethod, ffClone -} from './undo.js'; + init as undoInit, changeSelectedAttributeNoUndoMethod, + changeSelectedAttributeMethod +} 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'; -import { - init as eventInit, mouseMoveEvent, mouseUpEvent, mouseOutEvent, - dblClickEvent, mouseDownEvent, DOMMouseScrollEvent -} from './event.js'; -import { init as jsonInit, getJsonFromSvgElements, addSVGElementsFromJson } from './json.js'; -import { - init as elemInit, getResolutionMethod, getTitleMethod, setGroupTitleMethod, - setDocumentTitleMethod, setResolutionMethod, getEditorNSMethod, setBBoxZoomMethod, - setZoomMethod, setColorMethod, setGradientMethod, findDuplicateGradient, setPaintMethod, - setStrokeWidthMethod, setStrokeAttrMethod, getBoldMethod, setBoldMethod, getItalicMethod, - setItalicMethod, setTextAnchorMethod, getFontFamilyMethod, setFontFamilyMethod, setFontColorMethod, getFontColorMethod, - getFontSizeMethod, setFontSizeMethod, getTextMethod, setTextContentMethod, - setImageURLMethod, setLinkURLMethod, setRectRadiusMethod, makeHyperlinkMethod, - removeHyperlinkMethod, setSegTypeMethod, setBackgroundMethod -} 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 './text-actions.js' +import { init as eventInit } from './event.js' +import { init as jsonInit, getJsonFromSvgElements, addSVGElementsFromJson } from './json.js' +import * as elemGetSet from './elem-get-set.js' +import { init as selectedElemInit } from './selected-elem.js' import { init as blurInit, setBlurNoUndo, setBlurOffsets, setBlur -} from './blur-event.js'; -import { sanitizeSvg } from './sanitize.js'; -import { getReverseNS, NS } from '../common/namespaces.js'; +} from './blur-event.js' +import { sanitizeSvg } from './sanitize.js' +import { getReverseNS, NS } from './namespaces.js' import { - text2xml, assignAttributes, cleanupElement, getElem, getUrlFromAttr, - findDefs, getHref, setHref, getRefElem, getRotationAngle, getPathBBox, - preventClickDefault, walkTree, getBBoxOfElementAsPath, convertToPath, encode64, decode64, - getVisibleElements, dropXMLInternalSubset, init as utilsInit, - getBBox as utilsGetBBox, getStrokedBBoxDefaultVisible, isNullish, blankPageObjectURL, + assignAttributes, cleanupElement, getElement, getUrlFromAttr, + findDefs, getHref, setHref, getRefElem, getRotationAngle, + getBBoxOfElementAsPath, convertToPath, encode64, decode64, + getVisibleElements, init as utilsInit, + getBBox as utilsGetBBox, getStrokedBBoxDefaultVisible, blankPageObjectURL, $id, $qa, $qq, getFeGaussianBlur, stringToHTML, insertChildAtIndex -} from './utilities.js'; +} from './utilities.js' import { - transformPoint, matrixMultiply, hasMatrixTransform, transformListToTransform, - isIdentity, transformBox -} from './math.js'; + matrixMultiply, hasMatrixTransform, transformListToTransform +} from './math.js' import { - convertToNum, getTypeMap, init as unitsInit -} from '../common/units.js'; + convertToNum, init as unitsInit, getTypeMap +} from '../common/units.js' import { svgCanvasToString, svgToString, setSvgString, exportPDF, setUseDataMethod, init as svgInit, importSvgString, embedImage, rasterExport, uniquifyElemsMethod, removeUnusedDefElemsMethod, convertGradientsMethod -} from './svg-exec.js'; -import { - isChrome, isWebkit -} from '../common/browser.js'; // , supportsEditableText +} 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' -const { - MoveElementCommand, InsertElementCommand, RemoveElementCommand, - ChangeElementCommand, BatchCommand -} = hstry; +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 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'] -if (!window.console) { - window.console = {}; - window.console.log = function (_str) { /* empty fn */ }; - window.console.dir = function (_str) { /* empty fn */ }; -} +const THRESHOLD_DIST = 0.8 +const STEP_COUNT = 10 +const CLIPBOARD_ID = 'svgedit_clipboard' -if (window.opera) { - window.console.log = function (str) { window.opera.postError(str); }; - window.console.dir = function (_str) { /* empty fn */ }; -} - -// Reenable after fixing eslint-plugin-jsdoc to handle /** * The main SvgCanvas class that manages all SVG-related functions. * @memberof module:svgcanvas * -* @borrows module:coords.remapElement as #remapElement -* @borrows module:recalculate.recalculateDimensions as #recalculateDimensions -* -* @borrows module:utilities.cleanupElement as #cleanupElement -* @borrows module:utilities.getStrokedBBoxDefaultVisible as #getStrokedBBox -* @borrows module:utilities.getVisibleElements as #getVisibleElements -* @borrows module:utilities.findDefs as #findDefs -* @borrows module:utilities.getUrlFromAttr as #getUrlFromAttr -* @borrows module:utilities.getHref as #getHref -* @borrows module:utilities.setHref as #setHref -* @borrows module:utilities.getRotationAngle as #getRotationAngle -* @borrows module:utilities.getBBox as #getBBox -* @borrows module:utilities.getElem as #getElem -* @borrows module:utilities.getRefElem as #getRefElem -* @borrows module:utilities.assignAttributes as #assignAttributes -* -* @borrows module:math.matrixMultiply as #matrixMultiply -* @borrows module:math.hasMatrixTransform as #hasMatrixTransform -* @borrows module:math.transformListToTransform as #transformListToTransform -* @borrows module:units.convertToNum as #convertToNum -* @borrows module:sanitize.sanitizeSvg as #sanitizeSvg -* @borrows module:path.pathActions.linkControlPoints as #linkControlPoints */ 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) { - // Alias Namespace constants + constructor (container, config) { + // imported function made available as methods + this.initializeSvgCanvasMethods() + const { pathActions } = pathModule - // Default configuration options - let curConfig = { + // 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.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.encodableImages = {} + + this.curConfig = { // Default configuration options show_outside_canvas: true, selectNew: true, - dimensions: [ 640, 480 ] - }; - - // Update config with new one if given - this.mergeDeep = mergeDeep; - if (config) { - curConfig = this.mergeDeep(curConfig, config); + dimensions: [640, 480] } - - // Array with width/height of canvas - const { dimensions } = curConfig; - - const canvas = this; - - this.$id = $id; - this.$qq = $qq; - this.$qa = $qa; - this.encode64 = encode64; - this.decode64 = decode64; - this.stringToHTML = stringToHTML; - this.insertChildAtIndex = insertChildAtIndex; - this.getClosest = getClosest; - this.getParents = getParents; - /** A storage solution aimed at replacing jQuerys data function. - * Implementation Note: Elements are stored in a (WeakMap)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap]. - * This makes sure the data is garbage collected when the node is removed. - */ - this.dataStorage = { - _storage: new WeakMap(), - put: function (element, key, obj) { - if (!this._storage.has(element)) { - this._storage.set(element, new Map()); - } - this._storage.get(element).set(key, obj); - }, - get: function (element, key) { - return this._storage.get(element)?.get(key); - }, - has: function (element, key) { - return this._storage.has(element) && this._storage.get(element).has(key); - }, - remove: function (element, key) { - const ret = this._storage.get(element).delete(key); - if (!this._storage.get(element).size === 0) { - this._storage.delete(element); - } - return ret; - } - }; - const getDataStorage = this.getDataStorage = function () { return canvas.dataStorage; }; - - this.isLayer = draw.Layer.isLayer; + // Update config with new one if given + if (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 // "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. - const svgdoc = window.document; - + this.svgdoc = window.document + this.container = container // This is a container for the document being edited, not the document itself. - /** - * @name module:svgcanvas~svgroot - * @type {SVGSVGElement} - */ - const svgroot = svgRootElement(svgdoc, dimensions); - const getSVGRoot = () => svgroot; - container.append(svgroot); - - /** - * The actual element that represents the final output SVG element. - * @name module:svgcanvas~svgcontent - * @type {SVGSVGElement} - */ - let svgcontent = svgdoc.createElementNS(NS.SVG, 'svg'); - - /** -* This should really be an intersection implementing all rather than a union. -* @type {module:draw.DrawCanvasInit#getSVGContent|module:utilities.EditorContext#getSVGContent} -*/ - const getSVGContent = () => { return svgcontent; }; - - clearInit( - /** - * @implements {module:utilities.EditorContext} - */ - { - getSVGContent, - getDOMDocument() { return svgdoc; }, - getDOMContainer() { return container; }, - getSVGRoot, - getCurConfig() { return curConfig; } - } - ); - /** -* This function resets the svgcontent element while keeping it in the DOM. -* @function module:svgcanvas.SvgCanvas#clearSvgContentElement -* @returns {void} -*/ - const clearSvgContentElement = canvas.clearSvgContentElement = clearSvgContentElementInit; - clearSvgContentElement(); - - // Prefix string for element IDs - let idprefix = 'svg_'; - - /** -* Changes the ID prefix to the given value. -* @function module:svgcanvas.SvgCanvas#setIdPrefix -* @param {string} p - String with the new prefix -* @returns {void} -*/ - canvas.setIdPrefix = function (p) { - idprefix = p; - }; - - /** -* Current `draw.Drawing` object. -* @type {module:draw.Drawing} -* @name module:svgcanvas.SvgCanvas#current_drawing_ -*/ - canvas.current_drawing_ = new draw.Drawing(svgcontent, idprefix); - - /** -* Returns the current Drawing. -* @name module:svgcanvas.SvgCanvas#getCurrentDrawing -* @type {module:draw.DrawCanvasInit#getCurrentDrawing} -*/ - const getCurrentDrawing = canvas.getCurrentDrawing = function () { - return canvas.current_drawing_; - }; - - /** -* Float displaying the current zoom level (1 = 100%, .5 = 50%, etc.). -* @type {Float} -*/ - let currentZoom = 1; + 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) + // Float displaying the current zoom level (1 = 100%, .5 = 50%, etc.). + this.zoom = 1 // pointer to current group (for in-group editing) - let currentGroup = null; + this.currentGroup = null // Object containing data for the currently selected styles const allProperties = { shape: { - fill: (curConfig.initFill.color === 'none' ? '' : '#') + curConfig.initFill.color, + fill: (this.curConfig.initFill.color === 'none' ? '' : '#') + this.curConfig.initFill.color, fill_paint: null, - fill_opacity: curConfig.initFill.opacity, - stroke: '#' + curConfig.initStroke.color, + fill_opacity: this.curConfig.initFill.opacity, + stroke: '#' + this.curConfig.initStroke.color, stroke_paint: null, - stroke_opacity: curConfig.initStroke.opacity, - stroke_width: curConfig.initStroke.width, + stroke_opacity: this.curConfig.initStroke.opacity, + stroke_width: this.curConfig.initStroke.width, stroke_dasharray: 'none', stroke_linejoin: 'miter', stroke_linecap: 'butt', - opacity: curConfig.initOpacity + opacity: this.curConfig.initOpacity } - }; - allProperties.text = this.mergeDeep({}, allProperties.shape); - allProperties.text = this.mergeDeep(allProperties.text, { + } + allProperties.text = SvgCanvas.mergeDeep({}, allProperties.shape) + allProperties.text = SvgCanvas.mergeDeep(allProperties.text, { fill: '#000000', - stroke_width: curConfig.text && curConfig.text.stroke_width, - font_size: curConfig.text && curConfig.text.font_size, - font_family: curConfig.text && curConfig.text.font_family - }); + stroke_width: this.curConfig.text?.stroke_width, + font_size: this.curConfig.text?.font_size, + font_family: this.curConfig.text?.font_family + }) + this.curText = allProperties.text // Current text style properties // Current shape style properties - const curShape = allProperties.shape; + 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 - let selectedElements = []; + this.selectedElements = [] - jsonInit( - /** - * @implements {module:json.jsonContext} - */ - { - getDOMDocument() { return svgdoc; }, - getDrawing() { return getCurrentDrawing(); }, - getCurShape() { return curShape; }, - getCurrentGroup() { return currentGroup; } - } - ); + jsonInit(this) + unitsInit(this) + utilsInit(this) + coordsInit(this) + recalculateInit(this) + selectInit(this) + undoInit(this) + selectionInit(this) - /** -* @typedef {PlainObject} module:svgcanvas.SVGAsJSON -* @property {string} element -* @property {PlainObject<string, string>} attr -* @property {module:svgcanvas.SVGAsJSON[]} children -*/ - - /** -* @function module:svgcanvas.SvgCanvas#getContentElem -* @param {Text|Element} data -* @returns {module:svgcanvas.SVGAsJSON} -*/ - const getJsonFromSvgElement = this.getJsonFromSvgElement = getJsonFromSvgElements; - - /** -* This should really be an intersection implementing all rather than a union. -* @name module:svgcanvas.SvgCanvas#addSVGElementFromJson -* @type {module:utilities.EditorContext#addSVGElementFromJson|module:path.EditorContext#addSVGElementFromJson} -*/ - const addSVGElementFromJson = this.addSVGElementFromJson = addSVGElementsFromJson; - - canvas.matrixMultiply = matrixMultiply; - canvas.hasMatrixTransform = hasMatrixTransform; - canvas.transformListToTransform = transformListToTransform; - - /** -* @type {module:utilities.EditorContext#getBaseUnit} -*/ - const getBaseUnit = () => { return curConfig.baseUnit; }; - - /** -* Initialize from units.js. -* Send in an object implementing the ElementContainer interface (see units.js). -*/ - unitsInit( - /** - * @implements {module:units.ElementContainer} - */ - { - getBaseUnit, - getElement: getElem, - getHeight() { return svgcontent.getAttribute('height') / currentZoom; }, - getWidth() { return svgcontent.getAttribute('width') / currentZoom; }, - getRoundDigits() { return saveOptions.round_digits; } - } - ); - - canvas.convertToNum = convertToNum; - - /** -* Should really be an intersection with all needing to apply rather than a union. -* @name module:svgcanvas.SvgCanvas#getSelectedElements -* @type {module:utilities.EditorContext#getSelectedElements|module:draw.DrawCanvasInit#getSelectedElements|module:path.EditorContext#getSelectedElements} -*/ - const getSelectedElements = this.getSelectedElems = function () { - return selectedElements; - }; - - this.setSelectedElements = function (key, value) { - selectedElements[key] = value; - }; - this.setEmptySelectedElements = function () { - selectedElements = []; - }; - - const { pathActions } = pathModule; - - /** -* This should actually be an intersection as all interfaces should be met. -* @type {module:utilities.EditorContext#getSVGRoot|module:recalculate.EditorContext#getSVGRoot|module:coords.EditorContext#getSVGRoot|module:path.EditorContext#getSVGRoot} -*/ - - utilsInit( - /** - * @implements {module:utilities.EditorContext} - */ - { - pathActions, // Ok since not modifying - getSVGContent, - addSVGElementFromJson, - getSelectedElements, - getDOMDocument() { return svgdoc; }, - getDOMContainer() { return container; }, - getSVGRoot, - // TODO: replace this mostly with a way to get the current drawing. - getBaseUnit, - getSnappingStep() { return curConfig.snappingStep; }, - getDataStorage - } - ); - - canvas.findDefs = findDefs; - canvas.getUrlFromAttr = getUrlFromAttr; - canvas.getHref = getHref; - canvas.setHref = setHref; - /* const getBBox = */ canvas.getBBox = utilsGetBBox; - canvas.getRotationAngle = getRotationAngle; - canvas.getElem = getElem; - canvas.getRefElem = getRefElem; - canvas.assignAttributes = assignAttributes; - - this.cleanupElement = cleanupElement; - - /** -* This should actually be an intersection not a union as all should apply. -* @type {module:coords.EditorContext#getGridSnapping|module:path.EditorContext#getGridSnapping} -*/ - const getGridSnapping = () => { return curConfig.gridSnapping; }; - - coordsInit( - /** - * @implements {module:coords.EditorContext} - */ - { - getDrawing() { return getCurrentDrawing(); }, - getDataStorage, - getSVGRoot, - getGridSnapping - } - ); - this.remapElement = remapElement; - - recalculateInit( - /** - * @implements {module:recalculate.EditorContext} - */ - { - getSVGRoot, - getStartTransform() { return startTransform; }, - setStartTransform(transform) { startTransform = transform; }, - getDataStorage - } - ); - this.recalculateDimensions = recalculateDimensions; - - // import from sanitize.js - const nsMap = getReverseNS(); - canvas.sanitizeSvg = sanitizeSvg; - - /** -* This should really be an intersection applying to all types rather than a union. -* @name module:svgcanvas.SvgCanvas#getZoom -* @type {module:path.EditorContext#getCurrentZoom|module:select.SVGFactory#getCurrentZoom} -*/ - const getCurrentZoom = this.getZoom = function () { return currentZoom; }; - - /** -* This method rounds the incoming value to the nearest value based on the `currentZoom` -* @name module:svgcanvas.SvgCanvas#round -* @type {module:path.EditorContext#round} -*/ - const round = this.round = function (val) { - return Number.parseInt(val * currentZoom) / currentZoom; - }; - - selectInit( - curConfig, - /** - * Export to select.js. - * @implements {module:select.SVGFactory} - */ - { - createSVGElement(jsonMap) { return canvas.addSVGElementFromJson(jsonMap); }, - svgRoot() { return svgroot; }, - svgContent() { return svgcontent; }, - getDataStorage, - getCurrentZoom - } - ); - /** -* This object manages selectors for us. -* @name module:svgcanvas.SvgCanvas#selectorManager -* @type {module:select.SelectorManager} -*/ - const selectorManager = this.selectorManager = getSelectorManager(); - - /** -* @name module:svgcanvas.SvgCanvas#getNextId -* @type {module:path.EditorContext#getNextId} -*/ - const getNextId = canvas.getNextId = function () { - return getCurrentDrawing().getNextId(); - }; - - /** -* @name module:svgcanvas.SvgCanvas#getId -* @type {module:path.EditorContext#getId} -*/ - const getId = canvas.getId = function () { - return getCurrentDrawing().getId(); - }; - - /** -* The "implements" should really be an intersection applying to all types rather than a union. -* @name module:svgcanvas.SvgCanvas#call -* @type {module:draw.DrawCanvasInit#call|module:path.EditorContext#call} -*/ - const call = function (ev, arg) { - if (events[ev]) { - return events[ev](window, arg); - } - return undefined; - }; - - const restoreRefElems = function (elem) { - // Look for missing reference elements, restore any found - const attrs = {}; - refAttrs.forEach(function (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); - if (!ref) { - findDefs().append(removedElements[id]); - delete removedElements[id]; - } - } - }); - - const childs = elem.getElementsByTagName('*'); - - if (childs.length) { - for (let i = 0, l = childs.length; i < l; i++) { - restoreRefElems(childs[i]); - } - } - }; - - undoInit( - /** - * @implements {module:undo.undoContext} - */ - { - call, - restoreRefElems, - getSVGContent, - getCanvas() { return canvas; }, - getCurrentMode() { return currentMode; }, - getCurrentZoom, - getSVGRoot, - getSelectedElements - } - ); - - /** -* @name undoMgr -* @memberof module:svgcanvas.SvgCanvas# -* @type {module:history.HistoryEventHandler} -*/ - const undoMgr = canvas.undoMgr = getUndoManager(); - - /** -* This should really be an intersection applying to all types rather than a union. -* @name module:svgcanvas~addCommandToHistory -* @type {module:path.EditorContext#addCommandToHistory|module:draw.DrawCanvasInit#addCommandToHistory} -*/ - const addCommandToHistory = function (cmd) { - canvas.undoMgr.addCommandToHistory(cmd); - }; - selectionInit( - /** - * @implements {module:selection.selectionContext} - */ - { - getCanvas() { return canvas; }, - getDataStorage, - getCurrentGroup() { return currentGroup; }, - getSelectedElements, - getSVGRoot, - getSVGContent, - getDOMContainer() { return container; }, - getExtensions() { return extensions; }, - setExtensions(key, value) { extensions[key] = value; }, - getCurrentZoom, - getRubberBox() { return rubberBox; }, - setCurBBoxes(value) { curBBoxes = value; }, - getCurBBoxes(_value) { return curBBoxes; }, - getCurrentResizeMode() { return currentResizeMode; }, - addCommandToHistory, - getSelector() { return Selector; } - } - ); - - /** -* Clears the selection. The 'selected' handler is then optionally called. -* This should really be an intersection applying to all types rather than a union. -* @name module:svgcanvas.SvgCanvas#clearSelection -* @type {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection} -* @fires module:svgcanvas.SvgCanvas#event:selected -*/ - const clearSelection = this.clearSelection = clearSelectionMethod; - - /** -* Adds a list of elements to the selection. The 'selected' handler is then called. -* @name module:svgcanvas.SvgCanvas#addToSelection -* @type {module:path.EditorContext#addToSelection} -* @fires module:svgcanvas.SvgCanvas#event:selected -*/ - const addToSelection = this.addToSelection = addToSelectionMethod; - - /** - * @type {module:path.EditorContext#getOpacity} - */ - const getOpacity = function () { - return curShape.opacity; - }; - - /** - * @name module:svgcanvas.SvgCanvas#getMouseTarget - * @type {module:path.EditorContext#getMouseTarget} - */ - const getMouseTarget = this.getMouseTarget = getMouseTargetMethod; - - /** -* @namespace {module:path.pathActions} pathActions -* @memberof module:svgcanvas.SvgCanvas# -* @see module:path.pathActions -*/ - canvas.pathActions = pathActions; - /** -* @type {module:path.EditorContext#resetD} -*/ - function resetD(p) { - if (typeof pathActions.convertPath === 'function') { - p.setAttribute('d', pathActions.convertPath(p)); - } else if (typeof pathActions.convertPaths === 'function') { - p.setAttribute('d', pathActions.convertPaths(p)); - } - } - pathModule.init( - /** - * @implements {module:path.EditorContext} - */ - { - selectorManager, // Ok since not changing - canvas, // Ok since not changing - call, - resetD, - round, - clearSelection, - addToSelection, - addCommandToHistory, - remapElement, - addSVGElementFromJson, - getGridSnapping, - getOpacity, - getSelectedElements, - getContainer() { - return container; - }, - setStarted(s) { - started = s; - }, - getRubberBox() { - return rubberBox; - }, - setRubberBox(rb) { - rubberBox = rb; - return rubberBox; - }, - /** - * @param {PlainObject} ptsInfo - * @param {boolean} ptsInfo.closedSubpath - * @param {SVGCircleElement[]} ptsInfo.grips - * @fires module:svgcanvas.SvgCanvas#event:pointsAdded - * @fires module:svgcanvas.SvgCanvas#event:selected - * @returns {void} - */ - addPtsToSelection({ closedSubpath, grips }) { - // TODO: Correct this: - pathActions.canDeleteNodes = true; - pathActions.closed_subpath = closedSubpath; - call('pointsAdded', { closedSubpath, grips }); - call('selected', grips); - }, - /** - * @param {PlainObject} changes - * @param {ChangeElementCommand} changes.cmd - * @param {SVGPathElement} changes.elem - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - endChanges({ cmd, elem }) { - addCommandToHistory(cmd); - call('changed', [ elem ]); - }, - getCurrentZoom, - getId, - getNextId, - getMouseTarget, - getCurrentMode() { - return currentMode; - }, - setCurrentMode(cm) { - currentMode = cm; - return currentMode; - }, - getDrawnPath() { - return drawnPath; - }, - setDrawnPath(dp) { - drawnPath = dp; - return drawnPath; - }, - getSVGRoot - } - ); + this.nsMap = getReverseNS() + this.selectorManager = getSelectorManager() + this.pathActions = pathActions + pathModule.init(this) // Interface strings, usually for title elements - const uiStrings = {}; + this.uiStrings = {} // Animation element to change the opacity of any newly created element - const opacAni = document.createElementNS(NS.SVG, 'animate'); - opacAni.setAttribute('attributeName', 'opacity'); - opacAni.setAttribute('begin', 'indefinite'); - opacAni.setAttribute('dur', 1); - opacAni.setAttribute('fill', 'freeze'); - svgroot.appendChild(opacAni); - - // (function () { - // TODO For Issue 208: this is a start on a thumbnail - // const svgthumb = svgdoc.createElementNS(NS.SVG, 'use'); - // svgthumb.setAttribute('width', '100'); - // svgthumb.setAttribute('height', '100'); - // setHref(svgthumb, '#svgcontent'); - // svgroot.append(svgthumb); - // }()); - - /** - * @typedef {PlainObject} module:svgcanvas.SaveOptions - * @property {boolean} apply - * @property {"embed"} [image] - * @property {Integer} round_digits - */ - - // Object to contain image data for raster images that were found encodable - const encodableImages = {}; - // Object with save options - /** - * @type {module:svgcanvas.SaveOptions} - */ - const saveOptions = { round_digits: 5 }; - // Object with IDs for imported files, to see if one was already added - const importIds = {}; - // Current text style properties - const curText = allProperties.text; - // Object to contain all included extensions - const extensions = {}; - // Map of deleted reference elements - const removedElements = {}; - - // String with image URL of last loadable image - let lastGoodImgUrl = `${curConfig.imgPath}/logo.svg`; - // Boolean indicating whether or not a draw action has been started - let started = false; - // String with an element's initial transform attribute value - let startTransform = null; - // String indicating the current editor mode - let currentMode = 'select'; - // String with the current direction in which an element is being resized - let currentResizeMode = 'none'; - // Current general properties - let curProperties = curShape; - // Array with selected elements' Bounding box object - // selectedBBoxes = new Array(1), - // The DOM element that was just selected - let justSelected = null; - // DOM element for selection rectangle drawn by the user - let rubberBox = null; - // Array of current BBoxes, used in getIntersectionList(). - let curBBoxes = []; - // Canvas point for the most recent right click - let lastClickPoint = null; - - this.runExtension = function (name, action, vars) { - return this.runExtensions(action, vars, false, (n) => n === name); - }; - /* eslint-disable max-len */ - /** -* @todo Consider: Should this return an array by default, so extension results aren't overwritten? -* @todo Would be easier to document if passing in object with key of action and vars as value; could then define an interface which tied both together -* @function module:svgcanvas.SvgCanvas#runExtensions -* @param {"mouseDown"|"mouseMove"|"mouseUp"|"zoomChanged"|"IDsUpdated"|"canvasUpdated"|"toolButtonStateUpdate"|"selectedChanged"|"elementTransition"|"elementChanged"|"langReady"|"langChanged"|"addLangData"|"onNewDocument"|"workareaResized"} action -* @param {module:svgcanvas.SvgCanvas#event:ext_mouseDown|module:svgcanvas.SvgCanvas#event:ext_mouseMove|module:svgcanvas.SvgCanvas#event:ext_mouseUp|module:svgcanvas.SvgCanvas#event:ext_zoomChanged|module:svgcanvas.SvgCanvas#event:ext_IDsUpdated|module:svgcanvas.SvgCanvas#event:ext_canvasUpdated|module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate|module:svgcanvas.SvgCanvas#event:ext_selectedChanged|module:svgcanvas.SvgCanvas#event:ext_elementTransition|module:svgcanvas.SvgCanvas#event:ext_elementChanged|module:svgcanvas.SvgCanvas#event:ext_langReady|module:svgcanvas.SvgCanvas#event:ext_langChanged|module:svgcanvas.SvgCanvas#event:ext_addLangData|module:svgcanvas.SvgCanvas#event:ext_onNewDocument|module:svgcanvas.SvgCanvas#event:ext_workareaResized|module:svgcanvas.ExtensionVarBuilder} [vars] -* @param {boolean} [returnArray] -* @param {module:svgcanvas.ExtensionNameFilter} nameFilter -* @returns {GenericArray<module:svgcanvas.ExtensionStatus>|module:svgcanvas.ExtensionStatus|false} See {@tutorial ExtensionDocs} on the ExtensionStatus. -*/ - /* eslint-enable max-len */ - - this.runExtensions = runExtensionsMethod; - - /** -* Add an extension to the editor. -* @function module:svgcanvas.SvgCanvas#addExtension -* @param {string} name - String with the ID of the extension. Used internally; no need for i18n. -* @param {module:svgcanvas.ExtensionInitCallback} [extInitFunc] - Function supplied by the extension with its data -* @param {module:svgcanvas.ExtensionInitArgs} initArgs -* @fires module:svgcanvas.SvgCanvas#event:extension_added -* @throws {TypeError|Error} `TypeError` if `extInitFunc` is not a function, `Error` -* if extension of supplied name already exists -* @returns {Promise<void>} Resolves to `undefined` -*/ - this.addExtension = async function (name, extInitFunc, { importLocale }) { - if (typeof extInitFunc !== 'function') { - throw new TypeError('Function argument expected for `svgcanvas.addExtension`'); - } - if (name in extensions) { - throw new Error('Cannot add extension "' + name + '", an extension by that name already exists.'); - } - // Provide private vars/funcs here. Is there a better way to do this? - /** - * @typedef {module:svgcanvas.PrivateMethods} module:svgcanvas.ExtensionArgumentObject - * @property {SVGSVGElement} svgroot See {@link module:svgcanvas~svgroot} - * @property {SVGSVGElement} svgcontent See {@link module:svgcanvas~svgcontent} - * @property {!(string|Integer)} nonce See {@link module:draw.Drawing#getNonce} - * @property {module:select.SelectorManager} selectorManager - * @property {module:SVGEditor~ImportLocale} importLocale - */ - /** - * @type {module:svgcanvas.ExtensionArgumentObject} - * @see {@link module:svgcanvas.PrivateMethods} source for the other methods/properties - */ - const argObj = canvas.mergeDeep(canvas.getPrivateMethods(), { - importLocale, - svgroot, - svgcontent, - nonce: getCurrentDrawing().getNonce(), - selectorManager - }); - const extObj = await extInitFunc(argObj); - if (extObj) { - extObj.name = name; - } - extensions[name] = extObj; - return call('extension_added', extObj); - }; - - /** -* This method sends back an array or a NodeList full of elements that -* intersect the multi-select rubber-band-box on the currentLayer only. -* -* We brute-force `getIntersectionList` for browsers that do not support it (Firefox). -* -* Reference: -* Firefox does not implement `getIntersectionList()`, see {@link https://bugzilla.mozilla.org/show_bug.cgi?id=501421}. -* @function module:svgcanvas.SvgCanvas#getIntersectionList -* @param {SVGRect} rect -* @returns {Element[]|NodeList} Bbox elements -*/ - const getIntersectionList = this.getIntersectionList = getIntersectionListMethod; - - this.getStrokedBBox = getStrokedBBoxDefaultVisible; - - this.getVisibleElements = getVisibleElements; - - /** -* Wrap an SVG element into a group element, mark the group as 'gsvg'. -* @function module:svgcanvas.SvgCanvas#groupSvgElem -* @param {Element} elem - SVG element to wrap -* @returns {void} -*/ - this.groupSvgElem = groupSvgElem; - - // Set scope for these functions - - // Object to contain editor event names and callback functions - const events = {}; - - canvas.call = call; - /** - * Array of what was changed (elements, layers). - * @event module:svgcanvas.SvgCanvas#event:changed - * @type {Element[]} - */ - /** - * Array of selected elements. - * @event module:svgcanvas.SvgCanvas#event:selected - * @type {Element[]} - */ - /** - * Array of selected elements. - * @event module:svgcanvas.SvgCanvas#event:transition - * @type {Element[]} - */ - /** - * The Element is always `SVGGElement`? - * If not `null`, will be the set current group element. - * @event module:svgcanvas.SvgCanvas#event:contextset - * @type {null|Element} - */ - /** - * @event module:svgcanvas.SvgCanvas#event:pointsAdded - * @type {PlainObject} - * @property {boolean} closedSubpath - * @property {SVGCircleElement[]} grips Grips elements - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:zoomed - * @type {PlainObject} - * @property {Float} x - * @property {Float} y - * @property {Float} width - * @property {Float} height - * @property {0.5|2} factor - * @see module:SVGEditor.BBoxObjectWithFactor - */ - /** - * @event module:svgcanvas.SvgCanvas#event:updateCanvas - * @type {PlainObject} - * @property {false} center - * @property {module:math.XYObject} newCtr - */ - /** - * @typedef {PlainObject} module:svgcanvas.ExtensionInitResponsePlusName - * @implements {module:svgcanvas.ExtensionInitResponse} - * @property {string} name The extension's resolved ID (whether explicit or based on file name) - */ - /** - * Generalized extension object response of - * [`init()`]{@link module:svgcanvas.ExtensionInitCallback} - * along with the name of the extension. - * @event module:svgcanvas.SvgCanvas#event:extension_added - * @type {module:svgcanvas.ExtensionInitResponsePlusName|void} - */ - /** - * @event module:svgcanvas.SvgCanvas#event:extensions_added - * @type {void} -*/ - /** - * @typedef {PlainObject} module:svgcanvas.Message - * @property {any} data The data - * @property {string} origin The origin - */ - /** - * @event module:svgcanvas.SvgCanvas#event:message - * @type {module:svgcanvas.Message} - */ - /** - * SVG canvas converted to string. - * @event module:svgcanvas.SvgCanvas#event:saved - * @type {string} - */ - /** - * @event module:svgcanvas.SvgCanvas#event:setnonce - * @type {!(string|Integer)} - */ - /** - * @event module:svgcanvas.SvgCanvas#event:unsetnonce - * @type {void} - */ - /** - * @event module:svgcanvas.SvgCanvas#event:zoomDone - * @type {void} -*/ - /** - * @event module:svgcanvas.SvgCanvas#event:cleared - * @type {void} -*/ - - /** - * @event module:svgcanvas.SvgCanvas#event:exported - * @type {module:svgcanvas.ImageExportedResults} - */ - /** - * @event module:svgcanvas.SvgCanvas#event:exportedPDF - * @type {module:svgcanvas.PDFExportedResults} - */ - /* eslint-disable max-len */ - /** - * Creating a cover-all class until {@link https://github.com/jsdoc3/jsdoc/issues/1545} may be supported. - * `undefined` may be returned by {@link module:svgcanvas.SvgCanvas#event:extension_added} if the extension's `init` returns `undefined` It is also the type for the following events "zoomDone", "unsetnonce", "cleared", and "extensions_added". - * @event module:svgcanvas.SvgCanvas#event:GenericCanvasEvent - * @type {module:svgcanvas.SvgCanvas#event:selected|module:svgcanvas.SvgCanvas#event:changed|module:svgcanvas.SvgCanvas#event:contextset|module:svgcanvas.SvgCanvas#event:pointsAdded|module:svgcanvas.SvgCanvas#event:extension_added|module:svgcanvas.SvgCanvas#event:extensions_added|module:svgcanvas.SvgCanvas#event:message|module:svgcanvas.SvgCanvas#event:transition|module:svgcanvas.SvgCanvas#event:zoomed|module:svgcanvas.SvgCanvas#event:updateCanvas|module:svgcanvas.SvgCanvas#event:saved|module:svgcanvas.SvgCanvas#event:exported|module:svgcanvas.SvgCanvas#event:exportedPDF|module:svgcanvas.SvgCanvas#event:setnonce|module:svgcanvas.SvgCanvas#event:unsetnonce|void} - */ - /* eslint-enable max-len */ - - /** - * The promise return, if present, resolves to `undefined` - * (`extension_added`, `exported`, `saved`). - * @typedef {Promise<void>|void} module:svgcanvas.EventHandlerReturn -*/ - - /** -* @callback module:svgcanvas.EventHandler -* @param {external:Window} win -* @param {module:svgcanvas.SvgCanvas#event:GenericCanvasEvent} arg -* @listens module:svgcanvas.SvgCanvas#event:GenericCanvasEvent -* @returns {module:svgcanvas.EventHandlerReturn} -*/ - /* eslint-disable max-len */ - /** -* Attaches a callback function to an event. -* @function module:svgcanvas.SvgCanvas#bind -* @param {"changed"|"contextset"|"selected"|"pointsAdded"|"extension_added"|"extensions_added"|"message"|"transition"|"zoomed"|"updateCanvas"|"zoomDone"|"saved"|"exported"|"exportedPDF"|"setnonce"|"unsetnonce"|"cleared"} ev - String indicating the name of the event -* @param {module:svgcanvas.EventHandler} f - The callback function to bind to the event -* @returns {module:svgcanvas.EventHandler} The previous event -*/ - /* eslint-enable max-len */ - canvas.bind = function (ev, f) { - const old = events[ev]; - events[ev] = f; - return old; - }; - - /** -* Runs the SVG Document through the sanitizer and then updates its paths. -* @function module:svgcanvas.SvgCanvas#prepareSvg -* @param {XMLDocument} newDoc - The SVG DOM document -* @returns {void} -*/ - this.prepareSvg = prepareSvg; - - /** -* Removes any old rotations if present, prepends a new rotation at the -* transformed center. -* @function module:svgcanvas.SvgCanvas#setRotationAngle -* @param {string|Float} val - The new rotation angle in degrees -* @param {boolean} preventUndo - Indicates whether the action should be undoable or not -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.setRotationAngle = setRotationAngle; - - /** -* Runs `recalculateDimensions` on the selected elements, -* adding the changes to a single batch command. -* @function module:svgcanvas.SvgCanvas#recalculateAllSelectedDimensions -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.recalculateAllSelectedDimensions = recalculateAllSelectedDimensions; - - /** - * Debug tool to easily see the current matrix in the browser's console. - * @function module:svgcanvas~logMatrix - * @param {SVGMatrix} m The matrix - * @returns {void} - */ - const logMatrix = function (m) { - console.info([ m.a, m.b, m.c, m.d, m.e, m.f ]); - }; - - // Root Current Transformation Matrix in user units - let rootSctm = null; - - /** -* Group: Selection. -*/ - - // TODO: do we need to worry about selectedBBoxes here? - - /** -* Selects only the given elements, shortcut for `clearSelection(); addToSelection()`. -* @function module:svgcanvas.SvgCanvas#selectOnly -* @param {Element[]} elems - an array of DOM elements to be selected -* @param {boolean} showGrips - Indicates whether the resize grips should be shown -* @returns {void} -*/ - const selectOnly = this.selectOnly = function (elems, showGrips) { - clearSelection(true); - addToSelection(elems, showGrips); - }; - - // TODO: could use slice here to make this faster? - // TODO: should the 'selected' handler - - /** -* Removes elements from the selection. -* @function module:svgcanvas.SvgCanvas#removeFromSelection -* @param {Element[]} elemsToRemove - An array of elements to remove from selection -* @returns {void} -*/ - /* const removeFromSelection = */ this.removeFromSelection = function (elemsToRemove) { - if (isNullish(selectedElements[0])) { return; } - if (!elemsToRemove.length) { return; } - - // find every element and remove it from our array copy - const newSelectedItems = []; - const len = selectedElements.length; - for (let i = 0; i < len; ++i) { - const elem = selectedElements[i]; - if (elem) { - // keep the item - if (!elemsToRemove.includes(elem)) { - newSelectedItems.push(elem); - } else { // remove the item and its selector - selectorManager.releaseSelector(elem); - } - } - } - // the copy becomes the master now - selectedElements = newSelectedItems; - }; - - /** -* Clears the selection, then adds all elements in the current layer to the selection. -* @function module:svgcanvas.SvgCanvas#selectAllInCurrentLayer -* @returns {void} -*/ - this.selectAllInCurrentLayer = function () { - const currentLayer = getCurrentDrawing().getCurrentLayer(); - if (currentLayer) { - currentMode = 'select'; - if (currentGroup) { - selectOnly(currentGroup.children); - } else { - selectOnly(currentLayer.children); - } - } - }; - - let drawnPath = null; - - // Mouse events - (function () { - const freehand = { - minx: null, - miny: null, - maxx: null, - maxy: null - }; - const THRESHOLD_DIST = 0.8; - const STEP_COUNT = 10; - let dAttr = null; - let startX = null; - let startY = null; - let rStartX = null; - let rStartY = null; - let initBbox = {}; - let sumDistance = 0; - const controllPoint2 = { x: 0, y: 0 }; - const controllPoint1 = { x: 0, y: 0 }; - let start = { x: 0, y: 0 }; - const end = { x: 0, y: 0 }; - let bSpline = { x: 0, y: 0 }; - let nextPos = { x: 0, y: 0 }; - let parameter; - let nextParameter; - - /** - * @function eventInit Initialize from event.js - * @returns {void} - */ - eventInit( - /** - * @implements {module:event.eventContext_} - */ - { - getStarted() { return started; }, - getCanvas() { return canvas; }, - getDataStorage, - getCurConfig() { return curConfig; }, - getCurrentMode() { return currentMode; }, - getrootSctm() { return rootSctm; }, - getStartX() { return startX; }, - setStartX(value) { startX = value; }, - getStartY() { return startY; }, - setStartY(value) { startY = value; }, - getRStartX() { return rStartX; }, - getRStartY() { return rStartY; }, - getRubberBox() { return rubberBox; }, - getInitBbox() { return initBbox; }, - getCurrentResizeMode() { return currentResizeMode; }, - getCurrentGroup() { return currentGroup; }, - getDrawnPath() { return drawnPath; }, - getJustSelected() { return justSelected; }, - getOpacAni() { return opacAni; }, - getParameter() { return parameter; }, - getNextParameter() { return nextParameter; }, - getStepCount() { return STEP_COUNT; }, - getThreSholdDist() { return THRESHOLD_DIST; }, - getSumDistance() { return sumDistance; }, - getStart(key) { return start[key]; }, - getEnd(key) { return end[key]; }, - getbSpline(key) { return bSpline[key]; }, - getNextPos(key) { return nextPos[key]; }, - getControllPoint1(key) { return controllPoint1[key]; }, - getControllPoint2(key) { return controllPoint2[key]; }, - getFreehand(key) { return freehand[key]; }, - getDrawing() { return getCurrentDrawing(); }, - getCurShape() { return curShape; }, - getDAttr() { return dAttr; }, - getLastGoodImgUrl() { return lastGoodImgUrl; }, - getCurText(key) { return curText[key]; }, - setDAttr(value) { dAttr = value; }, - setEnd(key, value) { end[key] = value; }, - setControllPoint1(key, value) { controllPoint1[key] = value; }, - setControllPoint2(key, value) { controllPoint2[key] = value; }, - setJustSelected(value) { justSelected = value; }, - setParameter(value) { parameter = value; }, - setStart(value) { start = value; }, - setRStartX(value) { rStartX = value; }, - setRStartY(value) { rStartY = value; }, - setSumDistance(value) { sumDistance = value; }, - setbSpline(value) { bSpline = value; }, - setNextPos(value) { nextPos = value; }, - setNextParameter(value) { nextParameter = value; }, - setCurProperties(key, value) { curProperties[key] = value; }, - setCurText(key, value) { curText[key] = value; }, - setStarted(s) { started = s; }, - setStartTransform(transform) { startTransform = transform; }, - setCurrentMode(cm) { - currentMode = cm; - return currentMode; - }, - setFreehand(key, value) { freehand[key] = value; }, - setCurBBoxes(value) { curBBoxes = value; }, - setRubberBox(value) { rubberBox = value; }, - setInitBbox(value) { initBbox = value; }, - setRootSctm(value) { rootSctm = value; }, - setCurrentResizeMode(value) { currentResizeMode = value; }, - setLastClickPoint(value) { lastClickPoint = value; }, - getSelectedElements, - getCurrentZoom, - getId, - addCommandToHistory, - getSVGRoot, - getSVGContent, - call, - getIntersectionList - } - ); - - /** - * Follows these conditions: - * - When we are in a create mode, the element is added to the canvas but the - * action is not recorded until mousing up. - * - When we are in select mode, select the element, remember the position - * and do nothing else. - * @param {MouseEvent} evt - * @fires module:svgcanvas.SvgCanvas#event:ext_mouseDown - * @returns {void} - */ - const mouseDown = mouseDownEvent; - - // in this function we do not record any state changes yet (but we do update - // any elements that are still being created, moved or resized on the canvas) - /** - * - * @param {MouseEvent} evt - * @fires module:svgcanvas.SvgCanvas#event:transition - * @fires module:svgcanvas.SvgCanvas#event:ext_mouseMove - * @returns {void} - */ - const mouseMove = mouseMoveEvent; - - // - in create mode, the element's opacity is set properly, we create an InsertElementCommand - // and store it on the Undo stack - // - in move/resize mode, the element's attributes which were affected by the move/resize are - // identified, a ChangeElementCommand is created and stored on the stack for those attrs - // this is done in when we recalculate the selected dimensions() - /** - * - * @param {MouseEvent} evt - * @fires module:svgcanvas.SvgCanvas#event:zoomed - * @fires module:svgcanvas.SvgCanvas#event:changed - * @fires module:svgcanvas.SvgCanvas#event:ext_mouseUp - * @returns {void} - */ - const mouseUp = mouseUpEvent; - const mouseOut = mouseOutEvent; - - const dblClick = dblClickEvent; - - // prevent links from being followed in the canvas - const handleLinkInCanvas = function (e) { - e.preventDefault(); - return false; - }; - - // Added mouseup to the container here. - // TODO(codedread): Figure out why after the Closure compiler, the window mouseup is ignored. - container.addEventListener('mousedown', mouseDown); - container.addEventListener('mousemove', mouseMove); - container.addEventListener('click', handleLinkInCanvas); - container.addEventListener('dblclick', dblClick); - container.addEventListener('mouseup', mouseUp); - container.addEventListener('mouseleave', mouseOut); - - // TODO(rafaelcastrocouto): User preference for shift key and zoom factor - container.addEventListener('mousewheel', DOMMouseScrollEvent); - container.addEventListener('DOMMouseScroll', DOMMouseScrollEvent); - - }()); - - textActionsInit( - /** - * @implements {module:text-actions.textActionsContext} - */ - { - getCanvas() { return canvas; }, - getrootSctm() { return rootSctm; }, - getSelectedElements, - getCurrentZoom, - getCurrentMode() { - return currentMode; - }, - setCurrentMode(cm) { - currentMode = cm; - return currentMode; - }, - getSVGRoot, - call - } - ); - - const textActions = canvas.textActions = textActionsMethod; - - /** -* Group: Serialization. -*/ - this.getSvgOption = () => { return saveOptions; }; - this.setSvgOption = (key, value) => { saveOptions[key] = value; }; - - svgInit( - /** - * @implements {module:elem-get-set.elemInit} - */ - { - getCanvas() { return canvas; }, - getDataStorage, - getSVGContent, - getSVGRoot, - getUIStrings() { return uiStrings; }, - getCurrentGroup() { return currentGroup; }, - getCurConfig() { return curConfig; }, - getNsMap() { return nsMap; }, - getSvgOption: this.getSvgOption, - setSvgOption: this.setSvgOption, - getSvgOptionApply() { return saveOptions.apply; }, - getSvgOptionImages() { return saveOptions.images; }, - getEncodableImages(key) { return encodableImages[key]; }, - setEncodableImages(key, value) { encodableImages[key] = value; }, - call, - getDOMDocument() { return svgdoc; }, - getVisElems() { return visElems; }, - getIdPrefix() { return idprefix; }, - setCurrentZoom(value) { currentZoom = value; }, - getImportIds(key) { return importIds[key]; }, - setImportIds(key, value) { importIds[key] = value; }, - setRemovedElements(key, value) { removedElements[key] = value; }, - setSVGContent(value) { svgcontent = value; }, - getrefAttrs() { return refAttrs; }, - getcanvg() { return canvg; }, - addCommandToHistory - } - ); - - /** -* Looks at DOM elements inside the `<defs>` to see if they are referred to, -* removes them from the DOM if they are not. -* @function module:svgcanvas.SvgCanvas#removeUnusedDefElems -* @returns {Integer} The number of elements that were removed -*/ - this.removeUnusedDefElems = removeUnusedDefElemsMethod; - - /** -* Main function to set up the SVG content for output. -* @function module:svgcanvas.SvgCanvas#svgCanvasToString -* @returns {string} The SVG image for output -*/ - this.svgCanvasToString = svgCanvasToString; - - /** -* Sub function ran on each SVG element to convert it to a string as desired. -* @function module:svgcanvas.SvgCanvas#svgToString -* @param {Element} elem - The SVG element to convert -* @param {Integer} indent - Number of spaces to indent this tag -* @returns {string} The given element as an SVG tag -*/ - this.svgToString = svgToString; - - /** - * Function to run when image data is found. - * @callback module:svgcanvas.ImageEmbeddedCallback - * @param {string|false} result Data URL - * @returns {void} - */ - /** -* Converts a given image file to a data URL when possible, then runs a given callback. -* @function module:svgcanvas.SvgCanvas#embedImage -* @param {string} src - The path/URL of the image -* @returns {Promise<string|false>} Resolves to a Data URL (string|false) -*/ - this.embedImage = embedImage; - - /** -* Sets a given URL to be a "last good image" URL. -* @function module:svgcanvas.SvgCanvas#setGoodImage -* @param {string} val -* @returns {void} -*/ - this.setGoodImage = function (val) { - lastGoodImgUrl = val; - }; - - /** -* @typedef {PlainObject} module:svgcanvas.IssuesAndCodes -* @property {string[]} issueCodes The locale-independent code names -* @property {string[]} issues The localized descriptions -*/ - - /** - * @typedef {"feGaussianBlur"|"foreignObject"|"[stroke-dasharray]"|"text"} module:svgcanvas.IssueCode - */ - /** -* @typedef {PlainObject} module:svgcanvas.ImageExportedResults -* @property {string} datauri Contents as a Data URL -* @property {string} bloburl May be the empty string -* @property {string} svg The SVG contents as a string -* @property {string[]} issues The localization messages of `issueCodes` -* @property {module:svgcanvas.IssueCode[]} issueCodes CanVG issues found with the SVG -* @property {"PNG"|"JPEG"|"BMP"|"WEBP"|"ICO"} type The chosen image type -* @property {"image/png"|"image/jpeg"|"image/bmp"|"image/webp"} mimeType The image MIME type -* @property {Float} quality A decimal between 0 and 1 (for use with JPEG or WEBP) -* @property {string} exportWindowName A convenience for passing along a `window.name` to target a window on which the export could be added -*/ - - /** -* Generates a PNG (or JPG, BMP, WEBP) Data URL based on the current image, -* then calls "exported" with an object including the string, image -* information, and any issues found. -* @function module:svgcanvas.SvgCanvas#rasterExport -* @param {"PNG"|"JPEG"|"BMP"|"WEBP"|"ICO"} [imgType="PNG"] -* @param {Float} [quality] Between 0 and 1 -* @param {string} [exportWindowName] -* @param {PlainObject} [opts] -* @param {boolean} [opts.avoidEvent] -* @fires module:svgcanvas.SvgCanvas#event:exported -* @todo Confirm/fix ICO type -* @returns {Promise<module:svgcanvas.ImageExportedResults>} Resolves to {@link module:svgcanvas.ImageExportedResults} -*/ - this.rasterExport = rasterExport; - - /** - * @typedef {void|"save"|"arraybuffer"|"blob"|"datauristring"|"dataurlstring"|"dataurlnewwindow"|"datauri"|"dataurl"} external:jsPDF.OutputType - * @todo Newer version to add also allows these `outputType` values "bloburi"|"bloburl" which return strings, so document here and for `outputType` of `module:svgcanvas.PDFExportedResults` below if added -*/ - /** -* @typedef {PlainObject} module:svgcanvas.PDFExportedResults -* @property {string} svg The SVG PDF output -* @property {string|ArrayBuffer|Blob|window} output The output based on the `outputType`; -* if `undefined`, "datauristring", "dataurlstring", "datauri", -* or "dataurl", will be a string (`undefined` gives a document, while the others -* build as Data URLs; "datauri" and "dataurl" change the location of the current page); if -* "arraybuffer", will return `ArrayBuffer`; if "blob", returns a `Blob`; -* if "dataurlnewwindow", will change the current page's location and return a string -* if in Safari and no window object is found; otherwise opens in, and returns, a new `window` -* object; if "save", will have the same return as "dataurlnewwindow" if -* `navigator.getUserMedia` support is found without `URL.createObjectURL` support; otherwise -* returns `undefined` but attempts to save -* @property {external:jsPDF.OutputType} outputType -* @property {string[]} issues The human-readable localization messages of corresponding `issueCodes` -* @property {module:svgcanvas.IssueCode[]} issueCodes -* @property {string} exportWindowName -*/ - - /** -* Generates a PDF based on the current image, then calls "exportedPDF" with -* an object including the string, the data URL, and any issues found. -* @function module:svgcanvas.SvgCanvas#exportPDF -* @param {string} [exportWindowName] Will also be used for the download file name here -* @param {external:jsPDF.OutputType} [outputType="dataurlstring"] -* @fires module:svgcanvas.SvgCanvas#event:exportedPDF -* @returns {Promise<module:svgcanvas.PDFExportedResults>} Resolves to {@link module:svgcanvas.PDFExportedResults} -*/ - this.exportPDF = exportPDF; - - /** -* Returns the current drawing as raw SVG XML text. -* @function module:svgcanvas.SvgCanvas#getSvgString -* @returns {string} The current drawing as raw SVG XML text. -*/ - this.getSvgString = function () { - saveOptions.apply = false; - return this.svgCanvasToString(); - }; - - /** -* This function determines whether to use a nonce in the prefix, when -* generating IDs for future documents in SVG-Edit. -* If you're controlling SVG-Edit externally, and want randomized IDs, call -* this BEFORE calling `svgCanvas.setSvgString`. -* @function module:svgcanvas.SvgCanvas#randomizeIds -* @param {boolean} [enableRandomization] If true, adds a nonce to the prefix. Thus -* `svgCanvas.randomizeIds() <==> svgCanvas.randomizeIds(true)` -* @returns {void} -*/ - this.randomizeIds = function (enableRandomization) { - if (arguments.length > 0 && enableRandomization === false) { - draw.randomizeIds(false, getCurrentDrawing()); - } else { - draw.randomizeIds(true, getCurrentDrawing()); - } - }; - - /** -* Ensure each element has a unique ID. -* @function module:svgcanvas.SvgCanvas#uniquifyElems -* @param {Element} g - The parent element of the tree to give unique IDs -* @returns {void} -*/ - const uniquifyElems = this.uniquifyElems = uniquifyElemsMethod; - - /** -* Assigns reference data for each use element. -* @function module:svgcanvas.SvgCanvas#setUseData -* @param {Element} parent -* @returns {void} -*/ - const setUseData = this.setUseData = setUseDataMethod; - - /** -* Converts gradients from userSpaceOnUse to objectBoundingBox. -* @function module:svgcanvas.SvgCanvas#convertGradients -* @param {Element} elem -* @returns {void} -*/ - const convertGradients = this.convertGradients = convertGradientsMethod; - - /** -* This function sets the current drawing as the input SVG XML. -* @function module:svgcanvas.SvgCanvas#setSvgString -* @param {string} xmlString - The SVG as XML text. -* @param {boolean} [preventUndo=false] - Indicates if we want to do the -* changes without adding them to the undo stack - e.g. for initializing a -* drawing on page load. -* @fires module:svgcanvas.SvgCanvas#event:setnonce -* @fires module:svgcanvas.SvgCanvas#event:unsetnonce -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {boolean} This function returns `false` if the set was -* unsuccessful, `true` otherwise. -*/ - this.setSvgString = setSvgString; - - /** -* This function imports the input SVG XML as a `<symbol>` in the `<defs>`, then adds a -* `<use>` to the current layer. -* @function module:svgcanvas.SvgCanvas#importSvgString -* @param {string} xmlString - The SVG as XML text. -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {null|Element} This function returns null if the import was unsuccessful, or the element otherwise. -* @todo -* - properly handle if namespace is introduced by imported content (must add to svgcontent -* and update all prefixes in the imported node) -* - properly handle recalculating dimensions, `recalculateDimensions()` doesn't handle -* arbitrary transform lists, but makes some assumptions about how the transform list -* was obtained -*/ - this.importSvgString = importSvgString; - - // Could deprecate, but besides external uses, their usage makes clear that - // canvas is a dependency for all of these - const dr = { - identifyLayers, createLayer, cloneLayer, deleteCurrentLayer, - setCurrentLayer, renameCurrentLayer, setCurrentLayerPosition, - setLayerVisibility, moveSelectedToLayer, mergeLayer, mergeAllLayers, - leaveContext, setContext - }; - Object.entries(dr).forEach(([ prop, propVal ]) => { - canvas[prop] = propVal; - }); - draw.init( - /** - * @implements {module:draw.DrawCanvasInit} - */ - { - pathActions, - getDataStorage, - getCurrentGroup() { - return currentGroup; - }, - setCurrentGroup(cg) { - currentGroup = cg; - }, - getSelectedElements, - getSVGContent, - undoMgr, - getCurrentDrawing, - clearSelection, - call, - addCommandToHistory, - /** - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - changeSVGContent() { - call('changed', [ svgcontent ]); - } - } - ); - - /** -* Group: Document functions. -*/ - - /** -* Clears the current document. This is not an undoable action. -* @function module:svgcanvas.SvgCanvas#clear -* @fires module:svgcanvas.SvgCanvas#event:cleared -* @returns {void} -*/ - this.clear = function () { - pathActions.clear(); - - clearSelection(); - - // clear the svgcontent node - canvas.clearSvgContentElement(); - - // create new document - canvas.current_drawing_ = new draw.Drawing(svgcontent); - - // create empty first layer - canvas.createLayer('Layer 1'); - - // clear the undo stack - canvas.undoMgr.resetUndoStack(); - - // reset the selector manager - selectorManager.initGroup(); - - // reset the rubber band box - rubberBox = selectorManager.getRubberBandBox(); - - call('cleared'); - }; + 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) + + // prevent links from being followed in the canvas + const handleLinkInCanvas = (e) => { + e.preventDefault() + return false + } + container.addEventListener('mousedown', this.mouseDownEvent) + container.addEventListener('mousemove', this.mouseMoveEvent) + container.addEventListener('click', handleLinkInCanvas) + container.addEventListener('dblclick', this.dblClickEvent) + container.addEventListener('mouseup', this.mouseUpEvent) + container.addEventListener('mouseleave', this.mouseOutEvent) + container.addEventListener('mousewheel', this.DOMMouseScrollEvent) + container.addEventListener('DOMMouseScroll', this.DOMMouseScrollEvent) // Alias function - this.linkControlPoints = pathActions.linkControlPoints; + this.linkControlPoints = pathActions.linkControlPoints + this.curCommand = null + this.filter = null + this.filterHidden = false - /** -* @function module:svgcanvas.SvgCanvas#getContentElem -* @returns {Element} The content DOM element -*/ - this.getContentElem = function () { return svgcontent; }; - - /** -* @function module:svgcanvas.SvgCanvas#getRootElem -* @returns {SVGSVGElement} The root DOM element -*/ - this.getRootElem = function () { return svgroot; }; - - elemInit( - /** - * @implements {module:elem-get-set.elemInit} - */ - { - addCommandToHistory, - getCurrentZoom, - getSVGContent, - getSelectedElements, - call, - changeSelectedAttributeNoUndoMethod, - getDOMDocument() { return svgdoc; }, - getCanvas() { return canvas; }, - getDataStorage, - setCanvas(key, value) { canvas[key] = value; }, - setCurrentZoom(value) { currentZoom = value; }, - setCurProperties(key, value) { curProperties[key] = value; }, - getCurProperties(key) { return curProperties[key]; }, - setCurShape(key, value) { curShape[key] = value; }, - getCurText(key) { return curText[key]; }, - setCurText(key, value) { curText[key] = value; } - } - ); - - /** -* @typedef {PlainObject} DimensionsAndZoom -* @property {Float} w Width -* @property {Float} h Height -* @property {Float} zoom Zoom -*/ - - /** -* @function module:svgcanvas.SvgCanvas#getResolution -* @returns {DimensionsAndZoom} The current dimensions and zoom level in an object -*/ - const getResolution = this.getResolution = getResolutionMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getSnapToGrid -* @returns {boolean} The current snap to grid setting -*/ - this.getSnapToGrid = function () { return curConfig.gridSnapping; }; - - /** -* @function module:svgcanvas.SvgCanvas#getVersion -* @returns {string} A string which describes the revision number of SvgCanvas. -*/ - this.getVersion = function () { - return 'svgcanvas.js ($Rev$)'; - }; - - /** -* Update interface strings with given values. -* @function module:svgcanvas.SvgCanvas#setUiStrings -* @param {module:path.uiStrings} strs - Object with strings (see the [locales API]{@link module:locale.LocaleStrings} and the [tutorial]{@tutorial LocaleDocs}) -* @returns {void} -*/ - this.setUiStrings = function (strs) { - Object.assign(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} -*/ - this.setConfig = function (opts) { - Object.assign(curConfig, opts); - }; - - /** -* @function module:svgcanvas.SvgCanvas#getTitle -* @param {Element} [elem] -* @returns {string|void} the current group/SVG's title contents or -* `undefined` if no element is passed nd there are no selected elements. -*/ - this.getTitle = getTitleMethod; - - /** -* Sets the group/SVG's title content. -* @function module:svgcanvas.SvgCanvas#setGroupTitle -* @param {string} val -* @todo Combine this with `setDocumentTitle` -* @returns {void} -*/ - this.setGroupTitle = setGroupTitleMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getDocumentTitle -* @returns {string|void} The current document title or an empty string if not found -*/ - this.getDocumentTitle = function () { - return canvas.getTitle(svgcontent); - }; - - /** -* Adds/updates a title element for the document with the given name. -* This is an undoable action. -* @function module:svgcanvas.SvgCanvas#setDocumentTitle -* @param {string} newTitle - String with the new title -* @returns {void} -*/ - this.setDocumentTitle = setDocumentTitleMethod; - - /** -* Returns the editor's namespace URL, optionally adding it to the root element. -* @function module:svgcanvas.SvgCanvas#getEditorNS -* @param {boolean} [add] - Indicates whether or not to add the namespace value -* @returns {string} The editor's namespace URL -*/ - this.getEditorNS = getEditorNSMethod; - - /** -* Changes the document's dimensions to the given size. -* @function module:svgcanvas.SvgCanvas#setResolution -* @param {Float|"fit"} x - Number with the width of the new dimensions in user units. -* Can also be the string "fit" to indicate "fit to content". -* @param {Float} y - Number with the height of the new dimensions in user units. -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {boolean} Indicates if resolution change was successful. -* It will fail on "fit to content" option with no content to fit to. -*/ - this.setResolution = setResolutionMethod; - - /** -* @typedef {module:jQueryAttr.Attributes} module:svgcanvas.ElementPositionInCanvas -* @property {Float} x -* @property {Float} y -*/ - - /** -* @function module:svgcanvas.SvgCanvas#getOffset -* @returns {module:svgcanvas.ElementPositionInCanvas} An object with `x`, `y` values indicating the svgcontent element's -* position in the editor's canvas. -*/ - this.getOffset = function () { - return { x: Number(svgcontent.getAttribute('x')), y: Number(svgcontent.getAttribute('y')) }; - }; - - /** - * @typedef {PlainObject} module:svgcanvas.ZoomAndBBox - * @property {Float} zoom - * @property {module:utilities.BBoxObject} bbox - */ - /** -* Sets the zoom level on the canvas-side based on the given value. -* @function module:svgcanvas.SvgCanvas#setBBoxZoom -* @param {"selection"|"canvas"|"content"|"layer"|module:SVGEditor.BBoxObjectWithFactor} val - Bounding box object to zoom to or string indicating zoom option. Note: the object value type is defined in `svg-editor.js` -* @param {Integer} editorW - The editor's workarea box's width -* @param {Integer} editorH - The editor's workarea box's height -* @returns {module:svgcanvas.ZoomAndBBox|void} -*/ - this.setBBoxZoom = setBBoxZoomMethod; - - /** -* The zoom level has changed. Supplies the new zoom level as a number (not percentage). -* @event module:svgcanvas.SvgCanvas#event:ext_zoomChanged -* @type {Float} -*/ - /** -* The bottom panel was updated. -* @event module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate -* @type {PlainObject} -* @property {boolean} nofill Indicates fill is disabled -* @property {boolean} nostroke Indicates stroke is disabled -*/ - /** -* The element selection has changed (elements were added/removed from selection). -* @event module:svgcanvas.SvgCanvas#event:ext_selectedChanged -* @type {PlainObject} -* @property {Element[]} elems Array of the newly selected elements -* @property {Element|null} selectedElement The single selected element -* @property {boolean} multiselected Indicates whether one or more elements were selected -*/ - /** -* Called when part of element is in process of changing, generally on -* mousemove actions like rotate, move, etc. -* @event module:svgcanvas.SvgCanvas#event:ext_elementTransition -* @type {PlainObject} -* @property {Element[]} elems Array of transitioning elements -*/ - /** -* One or more elements were changed. -* @event module:svgcanvas.SvgCanvas#event:ext_elementChanged -* @type {PlainObject} -* @property {Element[]} elems Array of the affected elements -*/ - /** -* Invoked as soon as the locale is ready. -* @event module:svgcanvas.SvgCanvas#event:ext_langReady -* @type {PlainObject} -* @property {string} lang The two-letter language code -* @property {module:SVGEditor.uiStrings} uiStrings -* @property {module:SVGEditor~ImportLocale} importLocale -*/ - /** -* The language was changed. Two-letter code of the new language. -* @event module:svgcanvas.SvgCanvas#event:ext_langChanged -* @type {string} -*/ - /** -* Means for an extension to add locale data. The two-letter language code. -* @event module:svgcanvas.SvgCanvas#event:ext_addLangData -* @type {PlainObject} -* @property {string} lang -* @property {module:SVGEditor~ImportLocale} importLocale -*/ - /** - * Called when new image is created. - * @event module:svgcanvas.SvgCanvas#event:ext_onNewDocument - * @type {void} - */ - /** - * Called when sidepanel is resized or toggled. - * @event module:svgcanvas.SvgCanvas#event:ext_workareaResized - * @type {void} -*/ - /** - * Called upon addition of the extension, or, if svgicons are set, - * after the icons are ready when extension SVG icons have loaded. - * @event module:svgcanvas.SvgCanvas#event:ext_callback - * @type {void} -*/ - - /** -* Sets the zoom to the given level. -* @function module:svgcanvas.SvgCanvas#setZoom -* @param {Float} zoomLevel - Float indicating the zoom level to change to -* @fires module:svgcanvas.SvgCanvas#event:ext_zoomChanged -* @returns {void} -*/ - this.setZoom = setZoomMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getMode -* @returns {string} The current editor mode string -*/ - this.getMode = function () { - return currentMode; - }; - - /** -* Sets the editor's mode to the given string. -* @function module:svgcanvas.SvgCanvas#setMode -* @param {string} name - String with the new mode to change to -* @returns {void} -*/ - this.setMode = function (name) { - pathActions.clear(true); - textActions.clear(); - curProperties = (selectedElements[0] && selectedElements[0].nodeName === 'text') ? curText : curShape; - currentMode = name; - }; - - /** -* Group: Element Styling. -*/ - - /** -* @typedef {PlainObject} module:svgcanvas.PaintOptions -* @property {"solidColor"} type -*/ - - /** -* @function module:svgcanvas.SvgCanvas#getColor -* @param {string} type -* @returns {string|module:svgcanvas.PaintOptions|Float|module:jGraduate~Paint} The current fill/stroke option -*/ - this.getColor = function (type) { - return curProperties[type]; - }; - - /** -* Change the current stroke/fill color/gradient value. -* @function module:svgcanvas.SvgCanvas#setColor -* @param {string} type - String indicating fill or stroke -* @param {string} val - The value to set the stroke attribute to -* @param {boolean} preventUndo - Boolean indicating whether or not this should be an undoable option -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.setColor = setColorMethod; - - /** -* Apply the current gradient to selected element's fill or stroke. -* @function module:svgcanvas.SvgCanvas#setGradient -* @param {"fill"|"stroke"} type - String indicating "fill" or "stroke" to apply to an element -* @returns {void} -*/ - this.setGradient = setGradientMethod; - - /** -* Set a color/gradient to a fill/stroke. -* @function module:svgcanvas.SvgCanvas#setPaint -* @param {"fill"|"stroke"} type - String with "fill" or "stroke" -* @param {module:jGraduate.jGraduatePaintOptions} paint - The jGraduate paint object to apply -* @returns {void} -*/ - this.setPaint = setPaintMethod; - - /** -* @function module:svgcanvas.SvgCanvas#setStrokePaint -* @param {module:jGraduate~Paint} paint -* @returns {void} -*/ - this.setStrokePaint = function (paint) { - this.setPaint('stroke', paint); - }; - - /** -* @function module:svgcanvas.SvgCanvas#setFillPaint -* @param {module:jGraduate~Paint} paint -* @returns {void} -*/ - this.setFillPaint = function (paint) { - this.setPaint('fill', paint); - }; - - /** -* @function module:svgcanvas.SvgCanvas#getStrokeWidth -* @returns {Float|string} The current stroke-width value -*/ - this.getStrokeWidth = function () { - return curProperties.stroke_width; - }; - - /** -* Sets the stroke width for the current selected elements. -* When attempting to set a line's width to 0, this changes it to 1 instead. -* @function module:svgcanvas.SvgCanvas#setStrokeWidth -* @param {Float} val - A Float indicating the new stroke width value -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.setStrokeWidth = setStrokeWidthMethod; - - /** -* Set the given stroke-related attribute the given value for selected elements. -* @function module:svgcanvas.SvgCanvas#setStrokeAttr -* @param {string} attr - String with the attribute name -* @param {string|Float} val - String or number with the attribute value -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.setStrokeAttr = setStrokeAttrMethod; - - /** -* @typedef {PlainObject} module:svgcanvas.StyleOptions -* @property {string} fill -* @property {Float} fill_opacity -* @property {string} stroke -* @property {Float} stroke_width -* @property {string} stroke_dasharray -* @property {string} stroke_linejoin -* @property {string} stroke_linecap -* @property {Float} stroke_opacity -* @property {Float} opacity -*/ - - /** -* @function module:svgcanvas.SvgCanvas#getStyle -* @returns {module:svgcanvas.StyleOptions} current style options -*/ - this.getStyle = function () { - return curShape; - }; - - /** -* @function module:svgcanvas.SvgCanvas#getOpacity -* @returns {Float} the current opacity -*/ - this.getOpacity = getOpacity; - - /** -* Sets the given opacity on the current selected elements. -* @function module:svgcanvas.SvgCanvas#setOpacity -* @param {string} val -* @returns {void} -*/ - this.setOpacity = function (val) { - curShape.opacity = val; - changeSelectedAttribute('opacity', val); - }; - - /** -* @function module:svgcanvas.SvgCanvas#getFillOpacity -* @returns {Float} the current fill opacity -*/ - this.getFillOpacity = function () { - return curShape.fill_opacity; - }; - - /** -* @function module:svgcanvas.SvgCanvas#getStrokeOpacity -* @returns {string} the current stroke opacity -*/ - this.getStrokeOpacity = function () { - return curShape.stroke_opacity; - }; - - /** -* Sets the current fill/stroke opacity. -* @function module:svgcanvas.SvgCanvas#setPaintOpacity -* @param {string} type - String with "fill" or "stroke" -* @param {Float} val - Float with the new opacity value -* @param {boolean} preventUndo - Indicates whether or not this should be an undoable action -* @returns {void} -*/ - this.setPaintOpacity = function (type, val, preventUndo) { - curShape[type + '_opacity'] = val; - if (!preventUndo) { - changeSelectedAttribute(type + '-opacity', val); - } else { - changeSelectedAttributeNoUndo(type + '-opacity', val); - } - }; - - /** -* Gets the current fill/stroke opacity. -* @function module:svgcanvas.SvgCanvas#getPaintOpacity -* @param {"fill"|"stroke"} type - String with "fill" or "stroke" -* @returns {Float} Fill/stroke opacity -*/ - this.getPaintOpacity = function (type) { - return type === 'fill' ? this.getFillOpacity() : this.getStrokeOpacity(); - }; - - /** -* Gets the `stdDeviation` blur value of the given element. -* @function module:svgcanvas.SvgCanvas#getBlur -* @param {Element} elem - The element to check the blur value for -* @returns {string} stdDeviation blur attribute value -*/ - this.getBlur = function (elem) { - let val = 0; - // const elem = selectedElements[0]; - - if (elem) { - const filterUrl = elem.getAttribute('filter'); - if (filterUrl) { - const blur = getElem(elem.id + '_blur'); - if (blur) { - val = blur.firstChild.getAttribute('stdDeviation'); - } else { - const filterElem = getRefElem(filterUrl); - const blurElem = getFeGaussianBlur(filterElem); - if (blurElem !== null) { - val = blurElem.getAttribute('stdDeviation'); - } - } - } - } - return val; - }; - - (function () { - let curCommand = null; - let filter = null; - let filterHidden = false; - - blurInit( - /** - * @implements {module:elem-get-set.elemInit} - */ - { - getCanvas() { return canvas; }, - getCurCommand() { return curCommand; }, - setCurCommand(value) { curCommand = value; }, - getFilter() { return filter; }, - setFilter(value) { filter = value; }, - getFilterHidden() { return filterHidden; }, - setFilterHidden(value) { filterHidden = value; }, - changeSelectedAttributeNoUndoMethod, - changeSelectedAttributeMethod, - isWebkit, - addCommandToHistory, - getSelectedElements - } - ); - - /** -* Sets the `stdDeviation` blur value on the selected element without being undoable. -* @function module:svgcanvas.SvgCanvas#setBlurNoUndo -* @param {Float} val - The new `stdDeviation` value -* @returns {void} -*/ - canvas.setBlurNoUndo = setBlurNoUndo; - - /** -* Sets the `x`, `y`, `width`, `height` values of the filter element in order to -* make the blur not be clipped. Removes them if not neeeded. -* @function module:svgcanvas.SvgCanvas#setBlurOffsets -* @param {Element} filterElem - The filter DOM element to update -* @param {Float} stdDev - The standard deviation value on which to base the offset size -* @returns {void} -*/ - canvas.setBlurOffsets = setBlurOffsets; - - /** -* Adds/updates the blur filter to the selected element. -* @function module:svgcanvas.SvgCanvas#setBlur -* @param {Float} val - Float with the new `stdDeviation` blur value -* @param {boolean} complete - Whether or not the action should be completed (to add to the undo manager) -* @returns {void} -*/ - canvas.setBlur = setBlur; - }()); - - /** -* Check whether selected element is bold or not. -* @function module:svgcanvas.SvgCanvas#getBold -* @returns {boolean} Indicates whether or not element is bold -*/ - this.getBold = getBoldMethod; - - /** -* Make the selected element bold or normal. -* @function module:svgcanvas.SvgCanvas#setBold -* @param {boolean} b - Indicates bold (`true`) or normal (`false`) -* @returns {void} -*/ - this.setBold = setBoldMethod; - - /** -* Check whether selected element is in italics or not. -* @function module:svgcanvas.SvgCanvas#getItalic -* @returns {boolean} Indicates whether or not element is italic -*/ - this.getItalic = getItalicMethod; - - /** -* Make the selected element italic or normal. -* @function module:svgcanvas.SvgCanvas#setItalic -* @param {boolean} i - Indicates italic (`true`) or normal (`false`) -* @returns {void} -*/ - this.setItalic = setItalicMethod; - - /** -* Set the new text anchor. -* @function module:svgcanvas.SvgCanvas#setTextAnchor -* @param {string} textAnchor - The value of the text anchor (start, middle or end) -* @returns {void} -*/ - this.setTextAnchor = setTextAnchorMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getFontFamily -* @returns {string} The current font family -*/ - this.getFontFamily = getFontFamilyMethod; - - /** -* Set the new font family. -* @function module:svgcanvas.SvgCanvas#setFontFamily -* @param {string} val - String with the new font family -* @returns {void} -*/ - this.setFontFamily = setFontFamilyMethod; - - /** -* Set the new font color. -* @function module:svgcanvas.SvgCanvas#setFontColor -* @param {string} val - String with the new font color -* @returns {void} -*/ - this.setFontColor = setFontColorMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getFontColor -* @returns {string} The current font color -*/ - this.getFontColor = getFontColorMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getFontSize -* @returns {Float} The current font size -*/ - this.getFontSize = getFontSizeMethod; - - /** -* Applies the given font size to the selected element. -* @function module:svgcanvas.SvgCanvas#setFontSize -* @param {Float} val - Float with the new font size -* @returns {void} -*/ - this.setFontSize = setFontSizeMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getText -* @returns {string} The current text (`textContent`) of the selected element -*/ - this.getText = getTextMethod; - - /** -* Updates the text element with the given string. -* @function module:svgcanvas.SvgCanvas#setTextContent -* @param {string} val - String with the new text -* @returns {void} -*/ - this.setTextContent = setTextContentMethod; - - /** -* Sets the new image URL for the selected image element. Updates its size if -* a new URL is given. -* @function module:svgcanvas.SvgCanvas#setImageURL -* @param {string} val - String with the image URL/path -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.setImageURL = setImageURLMethod; - - /** -* Sets the new link URL for the selected anchor element. -* @function module:svgcanvas.SvgCanvas#setLinkURL -* @param {string} val - String with the link URL/path -* @returns {void} -*/ - this.setLinkURL = setLinkURLMethod; - - /** -* Sets the `rx` and `ry` values to the selected `rect` element -* to change its corner radius. -* @function module:svgcanvas.SvgCanvas#setRectRadius -* @param {string|Float} val - The new radius -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.setRectRadius = setRectRadiusMethod; - - /** -* Wraps the selected element(s) in an anchor element or converts group to one. -* @function module:svgcanvas.SvgCanvas#makeHyperlink -* @param {string} url -* @returns {void} -*/ - this.makeHyperlink = makeHyperlinkMethod; - - /** -* @function module:svgcanvas.SvgCanvas#removeHyperlink -* @returns {void} -*/ - this.removeHyperlink = removeHyperlinkMethod; - - /** -* Group: Element manipulation. -*/ - - /** -* Sets the new segment type to the selected segment(s). -* @function module:svgcanvas.SvgCanvas#setSegType -* @param {Integer} newType - New segment type. See {@link https://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg} for list -* @returns {void} -*/ - this.setSegType = setSegTypeMethod; - - /** -* Convert selected element to a path, or get the BBox of an element-as-path. -* @function module:svgcanvas.SvgCanvas#convertToPath -* @todo (codedread): Remove the getBBox argument and split this function into two. -* @param {Element} elem - The DOM element to be converted -* @param {boolean} getBBox - Boolean on whether or not to only return the path's BBox -* @returns {void|DOMRect|false|SVGPathElement|null} If the getBBox flag is true, the resulting path's bounding box object. -* Otherwise the resulting path element is returned. -*/ - this.convertToPath = function (elem, getBBox) { - if (isNullish(elem)) { - const elems = selectedElements; - elems.forEach(function(el){ - if (el) { canvas.convertToPath(el); } - }); - return undefined; - } - if (getBBox) { - return getBBoxOfElementAsPath(elem, addSVGElementFromJson, pathActions); - } - // TODO: Why is this applying attributes from curShape, then inside utilities.convertToPath it's pulling addition attributes from elem? - // TODO: If convertToPath is called with one elem, curShape and elem are probably the same; but calling with multiple is a bug or cool feature. - const attrs = { - fill: curShape.fill, - 'fill-opacity': curShape.fill_opacity, - stroke: curShape.stroke, - 'stroke-width': curShape.stroke_width, - 'stroke-dasharray': curShape.stroke_dasharray, - 'stroke-linejoin': curShape.stroke_linejoin, - 'stroke-linecap': curShape.stroke_linecap, - 'stroke-opacity': curShape.stroke_opacity, - opacity: curShape.opacity, - visibility: 'hidden' - }; - return convertToPath( - elem, attrs, addSVGElementFromJson, pathActions, - clearSelection, addToSelection, hstry, addCommandToHistory - ); - }; - - /** -* This function makes the changes to the elements. It does not add the change -* to the history stack. -* @param {string} attr - Attribute name -* @param {string|Float} newValue - String or number with the new attribute value -* @param {Element[]} elems - The DOM elements to apply the change to -* @returns {void} -*/ - const changeSelectedAttributeNoUndo = changeSelectedAttributeNoUndoMethod; - - /** -* Change the given/selected element and add the original value to the history stack. -* If you want to change all `selectedElements`, ignore the `elems` argument. -* If you want to change only a subset of `selectedElements`, then send the -* subset to this function in the `elems` argument. -* @function module:svgcanvas.SvgCanvas#changeSelectedAttribute -* @param {string} attr - String with the attribute name -* @param {string|Float} val - String or number with the new attribute value -* @param {Element[]} elems - The DOM elements to apply the change to -* @returns {void} -*/ - const changeSelectedAttribute = this.changeSelectedAttribute = changeSelectedAttributeMethod; - - /** -* Initialize from select-elem.js. -* Send in an object implementing the ElementContainer interface (see select-elem.js). -*/ - selectedElemInit( - /** - * @implements {module:selected-elem.elementContext} - */ - { - getSelectedElements, - addCommandToHistory, - getJsonFromSvgElement, - addSVGElementFromJson, - changeSelectedAttribute, - flashStorage, - call, - getIntersectionList, - setCurBBoxes(value) { curBBoxes = value; }, - getSVGRoot, - gettingSelectorManager() { return selectorManager; }, - getCurrentZoom, - getDrawing() { return getCurrentDrawing(); }, - getCurrentGroup() { return currentGroup; }, - addToSelection, - getContentW() { return canvas.contentW; }, - getContentH() { return canvas.contentH; }, - getClipboardID() { return CLIPBOARD_ID; }, - getDOMDocument() { return svgdoc; }, - clearSelection, - getNextId, - selectOnly, - uniquifyElems, - setUseData, - convertGradients, - getSVGContent, - getCanvas() { return canvas; }, - getDataStorage, - getVisElems() { return visElems; } - } - ); - - /** -* Removes all selected elements from the DOM and adds the change to the -* history stack. -* @function module:svgcanvas.SvgCanvas#deleteSelectedElements -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.deleteSelectedElements = deleteSelectedElements; - - /** -* Removes all selected elements from the DOM and adds the change to the -* history stack. Remembers removed elements on the clipboard. -* @function module:svgcanvas.SvgCanvas#cutSelectedElements -* @returns {void} -*/ - this.cutSelectedElements = function () { - canvas.copySelectedElements(); - canvas.deleteSelectedElements(); - }; - - const CLIPBOARD_ID = 'svgedit_clipboard'; - - /** -* Flash the clipboard data momentarily on localStorage so all tabs can see. -* @returns {void} -*/ - function flashStorage() { - const data = sessionStorage.getItem(CLIPBOARD_ID); - localStorage.setItem(CLIPBOARD_ID, data); - setTimeout(function () { - localStorage.removeItem(CLIPBOARD_ID); - }, 1); - } + blurInit(this) + selectedElemInit(this) /** * Transfers sessionStorage from one tab to another. * @param {!Event} ev Storage event. * @returns {void} */ - function storageChange(ev) { - if (!ev.newValue) return; // This is a call from removeItem. + const storageChange = (ev) => { + if (!ev.newValue) return // This is a call from removeItem. if (ev.key === CLIPBOARD_ID + '_startup') { // Another tab asked for our sessionStorage. - localStorage.removeItem(CLIPBOARD_ID + '_startup'); - flashStorage(); + 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()); - /** -* Remembers the current selected elements on the clipboard. -* @function module:svgcanvas.SvgCanvas#copySelectedElements -* @returns {void} -*/ - this.copySelectedElements = copySelectedElements; + localStorage.setItem(CLIPBOARD_ID + '_startup', Math.random()) - /** - * @function pasteInit Initialize from paste-elem.js. - * @returns {void} - * paste element functionality - */ - pasteInit( - /** - * @implements {module:event.eventContext_} - */ - { - getCanvas() { return canvas; }, - getClipBoardID() { return CLIPBOARD_ID; }, - getLastClickPoint(key) { return lastClickPoint[key]; }, - addCommandToHistory, - restoreRefElems - } - ); + pasteInit(this) - /** -* @function module:svgcanvas.SvgCanvas#pasteElements -* @param {"in_place"|"point"|void} type -* @param {Integer|void} x Expected if type is "point" -* @param {Integer|void} y Expected if type is "point" -* @fires module:svgcanvas.SvgCanvas#event:changed -* @fires module:svgcanvas.SvgCanvas#event:ext_IDsUpdated -* @returns {void} -*/ - this.pasteElements = pasteElementsMethod; - - /** -* Wraps all the selected elements in a group (`g`) element. -* @function module:svgcanvas.SvgCanvas#groupSelectedElements -* @param {"a"|"g"} [type="g"] - type of element to group into, defaults to `<g>` -* @param {string} [urlArg] -* @returns {void} -*/ - this.groupSelectedElements = groupSelectedElements; - - /** -* Pushes all appropriate parent group properties down to its children, then -* removes them from the group. -* @function module:svgcanvas.SvgCanvas#pushGroupProperties -* @param {SVGAElement|SVGGElement} g -* @param {boolean} undoable -* @returns {BatchCommand|void} -*/ - this.pushGroupProperties = pushGroupProperty; - - /** -* Unwraps all the elements in a selected group (`g`) element. This requires -* significant recalculations to apply group's transforms, etc. to its children. -* @function module:svgcanvas.SvgCanvas#ungroupSelectedElement -* @returns {void} -*/ - this.ungroupSelectedElement = ungroupSelectedElement; - - /** -* Repositions the selected element to the bottom in the DOM to appear on top of -* other elements. -* @function module:svgcanvas.SvgCanvas#moveToTopSelectedElement -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.moveToTopSelectedElement = moveToTopSelectedElem; - - /** -* Repositions the selected element to the top in the DOM to appear under -* other elements. -* @function module:svgcanvas.SvgCanvas#moveToBottomSelectedElement -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.moveToBottomSelectedElement = moveToBottomSelectedElem; - - /** -* Moves the select element up or down the stack, based on the visibly -* intersecting elements. -* @function module:svgcanvas.SvgCanvas#moveUpDownSelected -* @param {"Up"|"Down"} dir - String that's either 'Up' or 'Down' -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.moveUpDownSelected = moveUpDownSelected; - - /** -* Moves selected elements on the X/Y axis. -* @function module:svgcanvas.SvgCanvas#moveSelectedElements -* @param {Float} dx - Float with the distance to move on the x-axis -* @param {Float} dy - Float with the distance to move on the y-axis -* @param {boolean} undoable - Boolean indicating whether or not the action should be undoable -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {BatchCommand|void} Batch command for the move -*/ - this.moveSelectedElements = moveSelectedElements; - - /** -* Create deep DOM copies (clones) of all selected elements and move them slightly -* from their originals. -* @function module:svgcanvas.SvgCanvas#cloneSelectedElements -* @param {Float} x Float with the distance to move on the x-axis -* @param {Float} y Float with the distance to move on the y-axis -* @returns {void} -*/ - this.cloneSelectedElements = cloneSelectedElements; - - /** -* Aligns selected elements. -* @function module:svgcanvas.SvgCanvas#alignSelectedElements -* @param {string} type - String with single character indicating the alignment type -* @param {"selected"|"largest"|"smallest"|"page"} relativeTo -* @returns {void} -*/ - this.alignSelectedElements = alignSelectedElements; - - /** -* Group: Additional editor tools. -*/ - - /** -* @name module:svgcanvas.SvgCanvas#contentW -* @type {Float} -*/ - this.contentW = getResolution().w; - /** -* @name module:svgcanvas.SvgCanvas#contentH -* @type {Float} -*/ - this.contentH = getResolution().h; - - /** -* @typedef {PlainObject} module:svgcanvas.CanvasInfo -* @property {Float} x - The canvas' new x coordinate -* @property {Float} y - The canvas' new y coordinate -* @property {string} oldX - The canvas' old x coordinate -* @property {string} oldY - The canvas' old y coordinate -* @property {Float} d_x - The x position difference -* @property {Float} d_y - The y position difference -*/ - - /** -* Updates the editor canvas width/height/position after a zoom has occurred. -* @function module:svgcanvas.SvgCanvas#updateCanvas -* @param {Float} w - Float with the new width -* @param {Float} h - Float with the new height -* @fires module:svgcanvas.SvgCanvas#event:ext_canvasUpdated -* @returns {module:svgcanvas.CanvasInfo} -*/ - this.updateCanvas = updateCanvas; - - /** -* Set the background of the editor (NOT the actual document). -* @function module:svgcanvas.SvgCanvas#setBackground -* @param {string} color - String with fill color to apply -* @param {string} url - URL or path to image to use -* @returns {void} -*/ - this.setBackground = setBackgroundMethod; - - /** -* Select the next/previous element within the current layer. -* @function module:svgcanvas.SvgCanvas#cycleElement -* @param {boolean} next - true = next and false = previous element -* @fires module:svgcanvas.SvgCanvas#event:selected -* @returns {void} -*/ - this.cycleElement = cycleElement; - - this.clear(); - - /** -* @interface module:svgcanvas.PrivateMethods -* @type {PlainObject} -* @property {module:svgcanvas~addCommandToHistory} addCommandToHistory -* @property {module:history.HistoryCommand} BatchCommand -* @property {module:history.HistoryCommand} ChangeElementCommand -* @property {module:utilities.decode64} decode64 -* @property {module:utilities.dropXMLInternalSubset} dropXMLInternalSubset -* @property {module:utilities.encode64} encode64 -* @property {module:svgcanvas~ffClone} ffClone -* @property {module:svgcanvas~findDuplicateGradient} findDuplicateGradient -* @property {module:utilities.getPathBBox} getPathBBox -* @property {module:units.getTypeMap} getTypeMap -* @property {module:draw.identifyLayers} identifyLayers -* @property {module:history.HistoryCommand} InsertElementCommand -* @property {module:browser.isChrome} isChrome -* @property {module:math.isIdentity} isIdentity -* @property {module:svgcanvas~logMatrix} logMatrix -* @property {module:history.HistoryCommand} MoveElementCommand -* @property {module:namespaces.NS} NS -* @property {module:utilities.preventClickDefault} preventClickDefault -* @property {module:history.HistoryCommand} RemoveElementCommand -* @property {module:SVGTransformList.SVGEditTransformList} SVGEditTransformList -* @property {module:utilities.text2xml} text2xml -* @property {module:math.transformBox} transformBox -* @property {module:math.transformPoint} transformPoint -* @property {module:utilities.walkTree} walkTree -*/ - /** -* @deprecated getPrivateMethods -* Since all methods are/should be public somehow, this function should be removed; -* we might require `import` in place of this in the future once ES6 Modules -* widespread - -* Being able to access private methods publicly seems wrong somehow, -* but currently appears to be the best way to allow testing and provide -* access to them to plugins. -* @function module:svgcanvas.SvgCanvas#getPrivateMethods -* @returns {module:svgcanvas.PrivateMethods} -*/ - this.getPrivateMethods = function () { - return { - addCommandToHistory, - BatchCommand, - ChangeElementCommand, - decode64, - dropXMLInternalSubset, - encode64, - ffClone, - findDefs, - findDuplicateGradient, - getElem, - getPathBBox, - getTypeMap, - getUrlFromAttr, - identifyLayers: draw.identifyLayers, - InsertElementCommand, - isChrome, - isIdentity, - logMatrix, - MoveElementCommand, - NS, - preventClickDefault, - RemoveElementCommand, - text2xml, - transformBox, - transformPoint, - walkTree - }; - }; + 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.addSVGElementsFromJson(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 }) { + // TODO: Correct this: + 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 + * @param {SVGPathElement} changes.elem + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + endChanges ({ cmd, elem }) { + this.addCommandToHistory(cmd) + this.call('changed', [elem]) + } + + getCurrentMode () { return this.currentMode } + setCurrentMode (cm) { + this.currentMode = cm + return this.currentMode + } + + 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 } + 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 } + setCurProperties (key, value) { this.curProperties[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]?.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 the svgcontent node + this.clearSvgContentElement() + // create new document + this.current_drawing_ = new draw.Drawing(this.svgContent) + // create empty first layer + this.createLayer('Layer 1') + // clear the undo stack + this.undoMgr.resetUndoStack() + // reset the selector manager + this.selectorManager.initGroup() + // reset the rubber band box + this.rubberBox = this.selectorManager.getRubberBandBox() + this.call('cleared') + } + + runExtension (name, action, vars) { + return this.runExtensions(action, vars, false, (n) => n === name) + } + + async addExtension (name, extInitFunc, { importLocale }) { + if (typeof extInitFunc !== 'function') { + 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.') + } + const argObj = { + importLocale, + svgroot: this.svgroot, + 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) + } + + addCommandToHistory (cmd) { this.undoMgr.addCommandToHistory(cmd) } + restoreRefElements (elem) { + // Look for missing reference elements, restore any found + const attrs = {} + refAttrs.forEach((item, _) => { + attrs[item] = elem.getAttribute(item) + }) + Object.values(attrs).forEach((val) => { + if (val?.startsWith('url(')) { + const id = getUrlFromAttr(val).substr(1) + const ref = getElement(id) + if (!ref) { + findDefs().append(this.removedElements[id]) + delete this.removedElements[id] + } + } + }) + const childs = elem.getElementsByTagName('*') + + if (childs.length) { + for (let i = 0, l = childs.length; i < l; i++) { + this.restoreRefElements(childs[i]) + } + } + } + + call (ev, arg) { + if (this.events[ev]) { + return this.events[ev](window, arg) + } + return undefined + } + + /** + * Attaches a callback function to an event. + * @function module:svgcanvas.SvgCanvas#bind + * @param {string} ev - String indicating the name of the event + * @param {module:svgcanvas.EventHandler} f - The callback function to bind to the event + * @returns {module:svgcanvas.EventHandler} The previous event + */ + bind (ev, f) { + 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) + setTimeout(() => { + localStorage.removeItem(CLIPBOARD_ID) + }, 1) + } + + /** + * Selects only the given elements, shortcut for `clearSelection(); addToSelection()`. + * @function module:svgcanvas.SvgCanvas#selectOnly + * @param {Element[]} elems - an array of DOM elements to be selected + * @param {boolean} showGrips - Indicates whether the resize grips should be shown + * @returns {void} + */ + 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 (!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 + for (let i = 0; i < len; ++i) { + const elem = this.selectedElements[i] + if (elem) { + // keep the item + if (!elemsToRemove.includes(elem)) { + newSelectedItems.push(elem) + } else { // remove the item and its selector + this.selectorManager.releaseSelector(elem) + } + } + } + // the copy becomes the master now + 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() + if (currentLayer) { + this.currentMode = 'select' + if (this.currentGroup) { + this.selectOnly(this.currentGroup.children) + } else { + this.selectOnly(currentLayer.children) + } + } + } + + getOpacity () { + return this.curShape.opacity + } + + /** + * @function module:svgcanvas.SvgCanvas#getSnapToGrid + * @returns {boolean} The current snap to grid setting + */ + 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$)' } + /** + * 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) + } + + /** + * 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) } + /** + * @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')) } + } + + 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) } + /** + * @function module:svgcanvas.SvgCanvas#getStrokeWidth + * @returns {Float|string} The current stroke-width value + */ + getStrokeWidth () { return this.curProperties.stroke_width } + /** + * @function module:svgcanvas.SvgCanvas#getStyle + * @returns {module:svgcanvas.StyleOptions} current style options + */ + 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) + } + + /** + * @function module:svgcanvas.SvgCanvas#getFillOpacity + * @returns {Float} the current 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 } + /** + * Sets the current fill/stroke opacity. + * @function module:svgcanvas.SvgCanvas#setPaintOpacity + * @param {string} type - String with "fill" or "stroke" + * @param {Float} val - Float with the new opacity value + * @param {boolean} preventUndo - Indicates whether or not this should be an undoable action + * @returns {void} + */ + setPaintOpacity (type, val, preventUndo) { + this.curShape[type + '_opacity'] = val + if (!preventUndo) { + this.changeSelectedAttribute(type + '-opacity', val) + } else { + 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() + } + + /** + * 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 + if (elem) { + const filterUrl = elem.getAttribute('filter') + if (filterUrl) { + const blur = getElement(elem.id + '_blur') + if (blur) { + val = blur.firstChild.getAttribute('stdDeviation') + } else { + const filterElem = getRefElem(filterUrl) + const blurElem = getFeGaussianBlur(filterElem) + if (blurElem !== null) { + val = blurElem.getAttribute('stdDeviation') + } + } + } + } + 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 } + /** + * 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 function determines whether to use a nonce in the prefix, when + * generating IDs for future documents in SVG-Edit. + * If you're controlling SVG-Edit externally, and want randomized IDs, call + * this BEFORE calling `svgCanvas.setSvgString`. + * @function module:svgcanvas.SvgCanvas#randomizeIds + * @param {boolean} [enableRandomization] If true, adds a nonce to the prefix. Thus + * `svgCanvas.randomizeIds() <==> svgCanvas.randomizeIds(true)` + * @returns {void} + */ + randomizeIds (enableRandomization) { + if (arguments.length > 0 && enableRandomization === false) { + draw.randomizeIds(false, this.getCurrentDrawing()) + } else { + 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 + * @todo (codedread): Remove the getBBox argument and split this function into two. + * @param {Element} elem - The DOM element to be converted + * @param {boolean} getBBox - Boolean on whether or not to only return the path's BBox + * @returns {void|DOMRect|false|SVGPathElement|null} If the getBBox flag is true, the resulting path's bounding box object. + * Otherwise the resulting path element is returned. + */ + convertToPath (elem, getBBox) { + // if elems not given, recursively call convertPath for all selected elements. + if (!elem) { + const elems = this.selectedElements + elems.forEach((el) => { + if (el) { this.convertToPath(el) } + }) + return undefined + } + if (getBBox) { + return getBBoxOfElementAsPath(elem, this.addSVGElementsFromJson, 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. + const attrs = { + fill: this.curShape.fill, + 'fill-opacity': this.curShape.fill_opacity, + stroke: this.curShape.stroke, + 'stroke-width': this.curShape.stroke_width, + 'stroke-dasharray': this.curShape.stroke_dasharray, + 'stroke-linejoin': this.curShape.stroke_linejoin, + 'stroke-linecap': this.curShape.stroke_linecap, + 'stroke-opacity': this.curShape.stroke_opacity, + opacity: this.curShape.opacity, + visibility: 'hidden' + } + return convertToPath(elem, attrs, this) // call convertToPath from utilities.js + } + + /** + * 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() + } + + initializeSvgCanvasMethods () { + this.getJsonFromSvgElements = getJsonFromSvgElements + this.addSVGElementsFromJson = 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.getElement = getElement + 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.pasteElements = pasteElementsMethod // Remembers the current selected elements on the clipboard. + 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.hasTextDecoration = elemGetSet.hasTextDecorationMethod // Check whether the selected element has the given text decoration or not. + this.addTextDecoration = elemGetSet.addTextDecorationMethod // Adds the given value to the text decoration + this.removeTextDecoration = elemGetSet.removeTextDecorationMethod // Removes the given value from the text decoration + 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.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.isNullish = isNullish; -SvgCanvas.encode64 = encode64; -SvgCanvas.decode64 = decode64; -SvgCanvas.$id = $id; -SvgCanvas.$qq = $qq; -SvgCanvas.$qa = $qa; -SvgCanvas.mergeDeep = mergeDeep; -SvgCanvas.getClosest = getClosest; -SvgCanvas.getParents = getParents; -SvgCanvas.blankPageObjectURL = blankPageObjectURL; +SvgCanvas.$id = $id +SvgCanvas.$qq = $qq +SvgCanvas.$qa = $qa +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 fcc5cd38..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 '../common/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 68bb0dd9..3c9dd2c0 100644 --- a/src/svgcanvas/text-actions.js +++ b/src/svgcanvas/text-actions.js @@ -5,28 +5,27 @@ * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller */ - -import { NS } from '../common/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'; + assignAttributes, getElement, getBBox as utilsGetBBox +} from './utilities.js' import { supportsGoodTextCharPos -} from '../common/browser.js'; +} from '../common/browser.js' -let textActionsContext_ = null; +let svgCanvas = null /** * @function module:text-actions.init -* @param {module:text-actions.textActionsContext_} textActionsContext +* @param {module:text-actions.svgCanvas} textActionsContext * @returns {void} */ -export const init = function (textActionsContext) { - textActionsContext_ = textActionsContext; -}; +export const init = (canvas) => { + svgCanvas = canvas +} /** * Group: Text edit functions @@ -35,16 +34,16 @@ export const init = function (textActionsContext) { * @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 = getElement('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); + }) + getElement('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 = getElement('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); + }) + getElement('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 = textActionsContext_.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 currentZoom = textActionsContext_.getCurrentZoom(); - out.x /= currentZoom; - out.y /= currentZoom; + } + 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 currentZoom = textActionsContext_.getCurrentZoom(); - out.x *= currentZoom; - out.y *= currentZoom; + 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 currentZoom = textActionsContext_.getCurrentZoom(); - const ept = transformPoint(evt.pageX, evt.pageY, textActionsContext_.getrootSctm()); - const mouseX = ept.x * currentZoom; - const mouseY = ept.y * currentZoom; - 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; - textActionsContext_.getCanvas().textActions.toEditMode(x, y); + curtext = target + svgCanvas.textActions.toEditMode(x, y) }, /** * @param {Element} elem * @returns {void} */ start (elem) { - curtext = elem; - textActionsContext_.getCanvas().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,14 +347,14 @@ 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 // && !rectsIntersect(transbb, {x: pt.x, y: pt.y, width: 0, height: 0})) { - // textActionsContext_.getCanvas().textActions.toSelectMode(true); + // svgCanvas.textActions.toSelectMode(true); // } if ( @@ -365,7 +364,7 @@ export const textActionsMethod = (function () { mouseY < lastY + 2 && mouseY > lastY - 2 ) { - textActionsContext_.getCanvas().textActions.toSelectMode(true); + svgCanvas.textActions.toSelectMode(true) } }, /** @@ -380,16 +379,16 @@ export const textActionsMethod = (function () { * @returns {void} */ toEditMode (x, y) { - allowDbl = false; - textActionsContext_.setCurrentMode('textedit'); - textActionsContext_.getCanvas().selectorManager.requestSelector(curtext).showGrips(false); + allowDbl = false + svgCanvas.setCurrentMode('textedit') + svgCanvas.selectorManager.requestSelector(curtext).showGrips(false) // Make selector group accept clicks - /* const selector = */ textActionsContext_.getCanvas().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; - textActionsContext_.getCanvas().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) { - textActionsContext_.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) { - textActionsContext_.getCanvas().clearSelection(); - curtext.style.cursor = 'move'; + svgCanvas.clearSelection() + curtext.style.cursor = 'move' - textActionsContext_.call('selected', [ curtext ]); - textActionsContext_.getCanvas().addToSelection([ curtext ], true); + svgCanvas.call('selected', [curtext]) + svgCanvas.addToSelection([curtext], true) } - if (curtext && !curtext.textContent.length) { + if (!curtext?.textContent.length) { // No content, so delete - textActionsContext_.getCanvas().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 (textActionsContext_.getCurrentMode() === 'textedit') { - textActionsContext_.getCanvas().textActions.toSelectMode(); + if (svgCanvas.getCurrentMode() === 'textedit') { + 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 = textActionsContext_.getSelectedElements(); - curtext = selectedElements[0]; - textActionsContext_.getCanvas().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 currentZoom = textActionsContext_.getCurrentZoom(); - const offset = textActionsContext_.getCanvas().contentW * currentZoom; - start.x -= offset; - end.x -= offset; + const zoom = svgCanvas.getZoom() + const offset = svgCanvas.contentW * zoom + start.x -= offset + end.x -= offset - start.x /= currentZoom; - end.x /= currentZoom; + 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 ddf8d2c7..a7d68a96 100644 --- a/src/svgcanvas/undo.js +++ b/src/svgcanvas/undo.js @@ -4,34 +4,35 @@ * @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'; + getRotationAngle, getBBox as utilsGetBBox, setHref, getStrokedBBoxDefaultVisible +} 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 undoContext_ = null; +let svgCanvas = null /** * @function module:undo.init * @param {module:undo.undoContext} undoContext * @returns {void} */ -export const init = function (undoContext) { - undoContext_ = undoContext; -}; +export const init = (canvas) => { + svgCanvas = canvas + canvas.undoMgr = getUndoManager() +} -export const getUndoManager = function () { +export const getUndoManager = () => { return new UndoManager({ /** * @param {string} eventType One of the HistoryEvent types @@ -40,70 +41,70 @@ export const getUndoManager = function () { * @returns {void} */ handleHistoryEvent (eventType, cmd) { - const EventTypes = HistoryEventTypes; + const EventTypes = HistoryEventTypes // TODO: handle setBlurOffsets. if (eventType === EventTypes.BEFORE_UNAPPLY || eventType === EventTypes.BEFORE_APPLY) { - undoContext_.getCanvas().clearSelection(); + svgCanvas.clearSelection() } else if (eventType === EventTypes.AFTER_APPLY || eventType === EventTypes.AFTER_UNAPPLY) { - const elems = cmd.elements(); - undoContext_.getCanvas().pathActions.clear(); - undoContext_.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; - if (parent === undoContext_.getSVGContent()) { - draw.identifyLayers(); + const parent = isApply ? cmd.newParent : cmd.oldParent + if (parent === svgCanvas.getSvgContent()) { + draw.identifyLayers() } } else if (cmdType === 'InsertElementCommand' || cmdType === 'RemoveElementCommand') { - if (cmd.parent === undoContext_.getSVGContent()) { - draw.identifyLayers(); + if (cmd.parent === svgCanvas.getSvgContent()) { + draw.identifyLayers() } if (cmdType === 'InsertElementCommand') { if (isApply) { - undoContext_.restoreRefElems(cmd.elem); + svgCanvas.restoreRefElements(cmd.elem) } } else if (!isApply) { - undoContext_.restoreRefElems(cmd.elem); + svgCanvas.restoreRefElements(cmd.elem) } - if (cmd.elem && cmd.elem.tagName === 'use') { - undoContext_.getCanvas().setUseData(cmd.elem); + if (cmd.elem?.tagName === 'use') { + 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 === undoContext_.getSVGContent() + 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) { - undoContext_.getCanvas().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 @@ -116,15 +117,15 @@ export const getUndoManager = function () { * @returns {Element} Cloned element */ export const ffClone = function (elem) { - if (!isGecko()) { return elem; } - const clone = elem.cloneNode(true); - elem.before(clone); - elem.remove(); - undoContext_.getCanvas().selectorManager.releaseSelector(elem); - undoContext_.getCanvas().setSelectedElements(0, clone); - undoContext_.getCanvas().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 @@ -135,43 +136,43 @@ export const ffClone = function (elem) { * @returns {void} */ export const changeSelectedAttributeNoUndoMethod = function (attr, newValue, elems) { - const selectedElements = undoContext_.getSelectedElements(); - const currentZoom = undoContext_.getCurrentZoom(); - if (undoContext_.getCurrentMode() === 'pathedit') { + const selectedElements = svgCanvas.getSelectedElements() + const zoom = svgCanvas.getZoom() + if (svgCanvas.getCurrentMode() === 'pathedit') { // Editing node - undoContext_.getCanvas().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 (!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; - undoContext_.getCanvas().moveSelectedElements(diffX * currentZoom, diffY * currentZoom, 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 (!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 @@ -188,21 +189,21 @@ 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 // NOTE: Important that this happens AFTER elem.setAttribute() or else attributes like // font-size can get reset to their old value, ultimately by svgEditor.updateContextPanel(), // after calling textActions.toSelectMode() below - if (undoContext_.getCurrentMode() === 'textedit' && attr !== '#text' && elem.textContent.length) { - undoContext_.getCanvas().textActions.toSelectMode(elem); + if (svgCanvas.getCurrentMode() === 'textedit' && attr !== '#text' && elem.textContent.length) { + svgCanvas.textActions.toSelectMode(elem) } // if (i === 0) { @@ -214,50 +215,49 @@ 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 // that are not in the selectedElements array, we need to only request a // selector if the element is in that array if (selectedElements.includes(elem)) { - // eslint-disable-next-line no-loop-func setTimeout(function () { // Due to element replacement, this element may no longer // be part of the DOM - if (!elem.parentNode) { return; } - undoContext_.getCanvas().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 = undoContext_.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 = undoContext_.getSelectedElements(); - elems = elems || selectedElements; - undoContext_.getCanvas().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 = undoContext_.getCanvas().undoMgr.finishUndoableChange(); + const batchCmd = svgCanvas.undoMgr.finishUndoableChange() if (!batchCmd.isEmpty()) { - // undoContext_.addCommandToHistory(batchCmd); - undoContext_.getCanvas().undoMgr.addCommandToHistory(batchCmd); + // svgCanvas.addCommandToHistory(batchCmd); + svgCanvas.undoMgr.addCommandToHistory(batchCmd) } -}; +} diff --git a/src/svgcanvas/utilities.js b/src/svgcanvas/utilities.js index d068d5a7..b8e90261 100644 --- a/src/svgcanvas/utilities.js +++ b/src/svgcanvas/utilities.js @@ -6,33 +6,27 @@ * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller */ -import { NS } from '../common/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 { - isWebkit, supportsHVLineContainerBBox, supportsPathBBox -} from '../common/browser.js'; -import { getClosest, mergeDeep } from '../editor/components/jgraduate/Util.js'; - -// String used to encode base64. -const KEYSTR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; +} 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 editorContext_ = null; -let svgroot_ = null; +let svgCanvas = null +let svgroot_ = null /** * Object with the following keys/values. * @typedef {PlainObject} module:utilities.SVGElementJSON * @property {string} element - Tag name of the SVG element to create * @property {PlainObject<string, string>} attr - Has key-value attributes to assign to the new element. -* An `id` should be set so that {@link module:utilities.EditorContext#addSVGElementFromJson} can later re-identify the element for modification or replacement. +* An `id` should be set so that {@link module:utilities.EditorContext#addSVGElementsFromJson} can later re-identify the element for modification or replacement. * @property {boolean} [curStyles=false] - Indicates whether current style attributes should be applied first * @property {module:utilities.SVGElementJSON[]} [children] - Data objects to be added recursively as children * @property {string} [namespace="http://www.w3.org/2000/svg"] - Indicate a (non-SVG) namespace @@ -45,14 +39,14 @@ let svgroot_ = null; * @property {module:path.pathActions} pathActions */ /** - * @function module:utilities.EditorContext#getSVGContent + * @function module:utilities.EditorContext#getSvgContent * @returns {SVGSVGElement} */ /** * Create a new SVG element based on the given object keys/values and add it * to the current layer. * The element will be run through `cleanupElement` before being returned. - * @function module:utilities.EditorContext#addSVGElementFromJson + * @function module:utilities.EditorContext#addSVGElementsFromJson * @param {module:utilities.SVGElementJSON} data * @returns {Element} The new element */ @@ -69,7 +63,7 @@ let svgroot_ = null; * @returns {HTMLElement} */ /** - * @function module:utilities.EditorContext#getSVGRoot + * @function module:utilities.EditorContext#getSvgRoot * @returns {SVGSVGElement} */ /** @@ -83,13 +77,13 @@ let svgroot_ = null; /** * @function module:utilities.init -* @param {module:utilities.EditorContext} editorContext +* @param {module:utilities.EditorContext} canvas * @returns {void} */ -export const init = function (editorContext) { - editorContext_ = editorContext; - svgroot_ = editorContext.getSVGRoot(); -}; +export const init = (canvas) => { + svgCanvas = canvas + svgroot_ = canvas.getSvgRoot() +} /** * Used to prevent the [Billion laughs attack]{@link https://en.wikipedia.org/wiki/Billion_laughs_attack}. @@ -99,9 +93,9 @@ export const init = function (editorContext) { * @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. @@ -110,7 +104,7 @@ export const dropXMLInternalSubset = (str) => { * @param {string} str - The string to be converted * @returns {string} The converted string */ -export const toXml = function (str) { +export const toXml = (str) => { // ' is ok in XML, but not HTML // > does not normally need escaping, though it can if within a CDATA expression (and preceded by "]]") return str @@ -118,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. @@ -134,44 +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 - // input = convertToXMLReferences(input); - if (window.btoa) { - return window.btoa(input); // Use native if available - } - const output = new Array(Math.floor((input.length + 2) / 3) * 4); - - let i = 0; - let p = 0; - do { - const chr1 = input.charCodeAt(i++); - const chr2 = input.charCodeAt(i++); - const chr3 = input.charCodeAt(i++); - - /* eslint-disable no-bitwise */ - const enc1 = chr1 >> 2; - const enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - - let enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - let enc4 = chr3 & 63; - /* eslint-enable no-bitwise */ - - if (Number.isNaN(chr2)) { - enc3 = 64; - enc4 = 64; - } else if (Number.isNaN(chr3)) { - enc4 = 64; - } - - output[p++] = KEYSTR.charAt(enc1); - output[p++] = KEYSTR.charAt(enc2); - output[p++] = KEYSTR.charAt(enc3); - output[p++] = KEYSTR.charAt(enc4); - } while (i < input.length); - - return output.join(''); + input = encodeUTF8(input) // convert non-ASCII characters + return window.btoa(input) // Use native if available } /** @@ -180,39 +140,8 @@ export function encode64(input) { * @param {string} input Base64-encoded input * @returns {string} Decoded output */ -export function decode64(input) { - if (window.atob) { - return decodeUTF8(window.atob(input)); - } - - // remove all characters that are not A-Z, a-z, 0-9, +, /, or = - input = input.replace(/[^A-Za-z\d+/=]/g, ''); - - let output = ''; - let i = 0; - - do { - const enc1 = KEYSTR.indexOf(input.charAt(i++)); - const enc2 = KEYSTR.indexOf(input.charAt(i++)); - const enc3 = KEYSTR.indexOf(input.charAt(i++)); - const enc4 = KEYSTR.indexOf(input.charAt(i++)); - - /* eslint-disable no-bitwise */ - const chr1 = (enc1 << 2) | (enc2 >> 4); - const chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - const chr3 = ((enc3 & 3) << 6) | enc4; - /* eslint-enable no-bitwise */ - - output += String.fromCharCode(chr1); - - if (enc3 !== 64) { - output += String.fromCharCode(chr2); - } - if (enc4 !== 64) { - output += String.fromCharCode(chr3); - } - } while (i < input.length); - return decodeUTF8(output); +export function decode64 (input) { + return decodeUTF8(window.atob(input)) } /** @@ -220,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 @@ -230,9 +159,9 @@ export function decodeUTF8(argString) { * @param {string} argString * @returns {string} */ -export const encodeUTF8 = function (argString) { - return unescape(encodeURIComponent(argString)); -}; +export const encodeUTF8 = (argString) => { + return unescape(encodeURIComponent(argString)) +} /** * Convert dataURL to object URL. @@ -240,26 +169,26 @@ export const encodeUTF8 = function (argString) { * @param {string} dataurl * @returns {string} object URL or empty string */ -export const dataURLToObjectURL = function (dataurl) { +export const dataURLToObjectURL = (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. @@ -267,23 +196,23 @@ export const dataURLToObjectURL = function (dataurl) { * @param {Blob} blob A Blob object or File object * @returns {string} object URL or empty string */ -export const createObjectURL = function (blob) { +export const createObjectURL = (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 () { +export const blankPageObjectURL = (() => { 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). @@ -291,14 +220,14 @@ export const blankPageObjectURL = (function () { * @param {string} input * @returns {string} Decimal numeric character references */ -export const convertToXMLReferences = function (input) { +export const convertToXMLReferences = (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. @@ -308,27 +237,23 @@ export const convertToXMLReferences = function (input) { * @throws {Error} * @returns {XMLDocument} */ -export const text2xml = function (sXML) { +export const text2xml = (sXML) => { if (sXML.includes(' { + return { x, y, width, height } +} /** * @callback module:utilities.TreeWalker @@ -361,15 +286,15 @@ export const bboxToObj = function ({ x, y, width, height }) { * @param {module:utilities.TreeWalker} cbFn - Callback function to run on each element * @returns {void} */ -export const walkTree = function (elem, cbFn) { - if (elem && elem.nodeType === 1) { - cbFn(elem); - let i = elem.childNodes.length; +export const walkTree = (elem, cbFn) => { + if (elem?.nodeType === 1) { + cbFn(elem) + let i = elem.childNodes.length while (i--) { - walkTree(elem.childNodes.item(i), cbFn); + walkTree(elem.childNodes.item(i), cbFn) } } -}; +} /** * Walks the tree and executes the callback on each element in a depth-first fashion. @@ -379,15 +304,15 @@ export const walkTree = function (elem, cbFn) { * @param {module:utilities.TreeWalker} cbFn - Callback function to run on each element * @returns {void} */ -export const walkTreePost = function (elem, cbFn) { - if (elem && elem.nodeType === 1) { - let i = elem.childNodes.length; +export const walkTreePost = (elem, cbFn) => { + if (elem?.nodeType === 1) { + let i = elem.childNodes.length while (i--) { - walkTree(elem.childNodes.item(i), cbFn); + walkTree(elem.childNodes.item(i), cbFn) } - cbFn(elem); + cbFn(elem) } -}; +} /** * Extracts the URL from the `url(...)` syntax of some attributes. @@ -403,18 +328,18 @@ export const getUrlFromAttr = function (attrVal) { if (attrVal) { // url('#somegrad') if (attrVal.startsWith('url("')) { - return attrVal.substring(5, attrVal.indexOf('"', 6)); + return attrVal.substring(5, attrVal.indexOf('"', 6)) } // url('#somegrad') if (attrVal.startsWith("url('")) { - return attrVal.substring(5, attrVal.indexOf("'", 6)); + return attrVal.substring(5, attrVal.indexOf("'", 6)) } if (attrVal.startsWith('url(')) { - return attrVal.substring(4, attrVal.indexOf(')')); + return attrVal.substring(4, attrVal.indexOf(')')) } } - return null; -}; + return null +} /** * @function module:utilities.getHref @@ -422,8 +347,8 @@ export const getUrlFromAttr = function (attrVal) { * @returns {string} The given element's `xlink:href` value */ export let getHref = function (elem) { - return elem.getAttributeNS(NS.XLINK, 'href'); -}; + return elem.getAttributeNS(NS.XLINK, 'href') +} /** * Sets the given element's `xlink:href` value. @@ -433,30 +358,30 @@ export let getHref = function (elem) { * @returns {void} */ export let setHref = function (elem, val) { - elem.setAttributeNS(NS.XLINK, 'xlink:href', val); -}; + elem.setAttributeNS(NS.XLINK, 'xlink:href', val) +} /** * @function module:utilities.findDefs * @returns {SVGDefsElement} The document's `` element, creating it first if necessary */ export const findDefs = function () { - const svgElement = editorContext_.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 @@ -468,130 +393,75 @@ 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, checking for -* horizontal/vertical lines (see issue 717) -* Note that performance is currently terrible, so some way to improve would -* be great. -* @param {Element} selected - Container or `` DOM element -* @returns {DOMRect} Bounding box object -*/ -function groupBBFix(selected) { - if (supportsHVLineContainerBBox()) { - try { return selected.getBBox(); } catch (e) {/* empty */ } } - const ref = editorContext_.getDataStorage().get(selected, 'ref'); - let matched = null; - let ret; let copy; - - if (ref) { - const elements = []; - Array.prototype.forEach.call(ref.children, function (el) { - const elem = el.cloneNode(true); - elem.setAttribute('visibility', 'hidden'); - svgroot_.appendChild(elem); - copy.push(elem); - if ([ 'line', 'path' ].indexOf(elem.tagName) !== -1) { - elements.push(elem); - } - }); - matched = (elements.length) ? elements : null; - } else { - matched = selected.querySelectorAll('line, path'); - } - - let issue = false; - if (matched.length) { - Array.prototype.forEach.call(matched, function (match) { - const bb = match.getBBox(); - if (!bb.width || !bb.height) { - issue = true; - } - }); - if (issue) { - const elems = ref ? copy : selected.children; - ret = getStrokedBBox(elems); - } else { - ret = selected.getBBox(); - } - } else { - ret = selected.getBBox(); - } - if (ref) { - copy.remove(); - } - return ret; } /** @@ -602,72 +472,64 @@ function groupBBFix(selected) { * @returns {module:utilities.BBoxObject} Bounding box object */ export const getBBox = function (elem) { - const selected = elem || editorContext_.geSelectedElements()[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': - if (!supportsPathBBox()) { - ret = getPathBBox(selected); - } else if (selected.getBBox) { - ret = selected.getBBox(); - } - break; - case 'g': - case 'a': - ret = groupBBFix(selected); - 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 = groupBBFix(selected); // , true); - } - if (elname === 'use' || (elname === 'foreignObject' && isWebkit())) { - if (!ret) { ret = selected.getBBox(); } - - } 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 @@ -684,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. @@ -704,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. @@ -792,66 +654,66 @@ 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. * @function module:utilities.getBBoxOfElementAsPath * @param {Element} elem - The DOM element to be probed -* @param {module:utilities.EditorContext#addSVGElementFromJson} addSVGElementFromJson - Function to add the path element to the current layer. See canvas.addSVGElementFromJson +* @param {module:utilities.EditorContext#addSVGElementsFromJson} addSVGElementsFromJson - Function to add the path element to the current layer. See canvas.addSVGElementsFromJson * @param {module:path.pathActions} pathActions - If a transform exists, `pathActions.resetOrientation()` is used. See: canvas.pathActions. * @returns {DOMRect|false} The resulting path's bounding box object. */ -export const getBBoxOfElementAsPath = function (elem, addSVGElementFromJson, pathActions) { - const path = addSVGElementFromJson({ +export const getBBoxOfElementAsPath = function (elem, addSVGElementsFromJson, pathActions) { + const path = addSVGElementsFromJson({ 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. * @function module:utilities.convertToPath * @param {Element} elem - The DOM element to be converted * @param {module:utilities.SVGElementJSON} attrs - Apply attributes to new path. see canvas.convertToPath -* @param {module:utilities.EditorContext#addSVGElementFromJson} addSVGElementFromJson - Function to add the path element to the current layer. See canvas.addSVGElementFromJson +* @param {module:utilities.EditorContext#addSVGElementsFromJson} addSVGElementsFromJson - Function to add the path element to the current layer. See canvas.addSVGElementsFromJson * @param {module:path.pathActions} pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions. * @param {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection} clearSelection - see [canvas.clearSelection]{@link module:svgcanvas.SvgCanvas#clearSelection} * @param {module:path.EditorContext#addToSelection} addToSelection - see [canvas.addToSelection]{@link module:svgcanvas.SvgCanvas#addToSelection} @@ -859,65 +721,62 @@ export const getBBoxOfElementAsPath = function (elem, addSVGElementFromJson, pat * @param {module:path.EditorContext#addCommandToHistory|module:draw.DrawCanvasInit#addCommandToHistory} addCommandToHistory - see [canvas.addCommandToHistory]{@link module:svgcanvas~addCommandToHistory} * @returns {SVGPathElement|null} The converted path element or null if the DOM element was not recognized. */ -export const convertToPath = function ( - elem, attrs, addSVGElementFromJson, pathActions, - clearSelection, addToSelection, hstry, addCommandToHistory -) { - const batchCmd = new hstry.BatchCommand('Convert element to Path'); +export const convertToPath = (elem, attrs, svgCanvas) => { + const batchCmd = new svgCanvas.history.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 = addSVGElementFromJson({ + const path = svgCanvas.addSVGElementsFromJson({ 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); + svgCanvas.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 svgCanvas.history.RemoveElementCommand(elem, nextSibling, parent)) + batchCmd.addSubCommand(new svgCanvas.history.InsertElementCommand(path)) - clearSelection(); - elem.remove(); - path.setAttribute('id', id); - path.removeAttribute('visibility'); - addToSelection([ path ], true); + svgCanvas.clearSelection() + elem.remove() + path.setAttribute('id', id) + path.removeAttribute('visibility') + svgCanvas.addToSelection([path], true) - addCommandToHistory(batchCmd); + svgCanvas.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 @@ -939,77 +798,63 @@ export const convertToPath = function ( * @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) } /** * Get bounding box that includes any transforms. * @function module:utilities.getBBoxWithTransform * @param {Element} elem - The DOM element to be converted -* @param {module:utilities.EditorContext#addSVGElementFromJson} addSVGElementFromJson - Function to add the path element to the current layer. See canvas.addSVGElementFromJson +* @param {module:utilities.EditorContext#addSVGElementsFromJson} addSVGElementsFromJson - Function to add the path element to the current layer. See canvas.addSVGElementsFromJson * @param {module:path.pathActions} pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions. * @returns {module:utilities.BBoxObject|module:math.TransformedBox|DOMRect} A single bounding box object */ -export const getBBoxWithTransform = function (elem, addSVGElementFromJson, pathActions) { +export const getBBoxWithTransform = function (elem, addSVGElementsFromJson, pathActions) { // TODO: Fix issue with rotated groups. Currently they work // fine in FF, but not in other browsers (same problem mentioned // in Issue 339 comment #2). - let bb = getBBox(elem); + 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, addSVGElementFromJson, pathActions); - bb = goodBb; + goodBb = getBBoxOfElementAsPath(elem, addSVGElementsFromJson, 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, addSVGElementFromJson, pathActions); - bb = goodBb; + goodBb = getBBoxOfElementAsPath(elem, addSVGElementsFromJson, pathActions) + bb = goodBb } } } if (!goodBb) { - const { matrix } = transformListToTransform(tlist); - bb = transformBox(bb.x, bb.y, bb.width, bb.height, matrix).aabox; - - // Old technique that was exceedingly slow with large documents. - // - // Accurate way to get BBox of rotated element in Firefox: - // Put element in group and get its BBox - // - // Must use clone else FF freaks out - // const clone = elem.cloneNode(true); - // const g = document.createElementNS(NS.SVG, 'g'); - // const parent = elem.parentNode; - // parent.append(g); - // g.append(clone); - // const bb2 = bboxToObj(g.getBBox()); - // g.remove(); + const { matrix } = transformListToTransform(tlist) + bb = transformBox(bb.x, bb.y, bb.width, bb.height, matrix).aabox } } - return bb; -}; + return bb +} /** * @param {Element} elem @@ -1017,9 +862,9 @@ export const getBBoxWithTransform = function (elem, addSVGElementFromJson, 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; +const getStrokeOffsetForBBox = (elem) => { + const sw = elem.getAttribute('stroke-width') + return (!isNaN(sw) && elem.getAttribute('stroke') !== 'none') ? sw / 2 : 0 } /** @@ -1034,60 +879,60 @@ function getStrokeOffsetForBBox(elem) { * Get the bounding box for one or more stroked and/or transformed elements. * @function module:utilities.getStrokedBBox * @param {Element[]} elems - Array with DOM elements to check -* @param {module:utilities.EditorContext#addSVGElementFromJson} addSVGElementFromJson - Function to add the path element to the current layer. See canvas.addSVGElementFromJson +* @param {module:utilities.EditorContext#addSVGElementsFromJson} addSVGElementsFromJson - Function to add the path element to the current layer. See canvas.addSVGElementsFromJson * @param {module:path.pathActions} pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions. * @returns {module:utilities.BBoxObject|module:math.TransformedBox|DOMRect} A single bounding box object */ -export const getStrokedBBox = function (elems, addSVGElementFromJson, pathActions) { - if (!elems || !elems.length) { return false; } +export const getStrokedBBox = (elems, addSVGElementsFromJson, pathActions) => { + if (!elems || !elems.length) { return false } - let fullBb; - elems.forEach(function(elem){ - if (fullBb) { return; } - if (!elem.parentNode) { return; } - fullBb = getBBoxWithTransform(elem, addSVGElementFromJson, pathActions); - }); + let fullBb + elems.forEach((elem) => { + if (fullBb) { return } + if (!elem.parentNode) { return } + fullBb = getBBoxWithTransform(elem, addSVGElementsFromJson, pathActions) + }) // This shouldn't ever happen... - if (fullBb === undefined) { 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, addSVGElementFromJson, pathActions); + elems.forEach((elem) => { + const curBb = getBBoxWithTransform(elem, addSVGElementsFromJson, 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). @@ -1097,21 +942,22 @@ export const getStrokedBBox = function (elems, addSVGElementFromJson, pathAction * @param {Element} parentElement - The parent DOM element to search within * @returns {Element[]} All "visible" elements. */ -export const getVisibleElements = function (parentElement) { +export const getVisibleElements = (parentElement) => { if (!parentElement) { - const svgcontent = editorContext_.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 childrens = parentElement.children; - Array.prototype.forEach.call(childrens, 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. @@ -1119,14 +965,14 @@ export const getVisibleElements = function (parentElement) { * @param {Element[]} elems - Array with DOM elements to check * @returns {module:utilities.BBoxObject} A single bounding box object */ -export const getStrokedBBoxDefaultVisible = function (elems) { - if (!elems) { elems = getVisibleElements(); } +export const getStrokedBBoxDefaultVisible = (elems) => { + if (!elems) { elems = getVisibleElements() } return getStrokedBBox( elems, - editorContext_.addSVGElementFromJson, - editorContext_.pathActions - ); -}; + svgCanvas.addSVGElementsFromJson, + svgCanvas.pathActions + ) +} /** * Get the rotation angle of the given transform list. @@ -1136,15 +982,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. @@ -1153,12 +999,12 @@ export const getRotationAngleFromTransformList = (tlist, toRad) => { * @param {boolean} [toRad=false] - When true returns the value in radians rather than degrees * @returns {Float} The angle in degrees or radians */ -export let getRotationAngle = function (elem, toRad) { - const selected = elem || editorContext_.getSelectedElements()[0]; +export let getRotationAngle = (elem, toRad) => { + 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. @@ -1166,40 +1012,40 @@ export let getRotationAngle = function (elem, toRad) { * @param {string} attrVal - The attribute value as a string * @returns {Element} Reference element */ -export const getRefElem = function (attrVal) { - return getElem(getUrlFromAttr(attrVal).substr(1)); -}; +export const getRefElem = (attrVal) => { + return getElement(getUrlFromAttr(attrVal).substr(1)) +} /** * Get the reference element associated with the given attribute value. * @function module:utilities.getFeGaussianBlur * @param {any} Element * @returns {any} Reference element */ -export const getFeGaussianBlur = function (ele) { +export const getFeGaussianBlur = (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. -* @function module:utilities.getElem +* @function module:utilities.getElement * @param {string} id - String with the element's new ID * @returns {?Element} */ -export const getElem = (id) => { +export const getElement = (id) => { // querySelector lookup - return svgroot_.querySelector('#' + id); -}; + return svgroot_.querySelector('#' + id) +} /** * Assigns multiple attributes to an element. @@ -1210,28 +1056,28 @@ export const getElem = (id) => { * @param {boolean} [unitCheck=false] - Boolean to indicate the need to use units.setUnitAttr * @returns {void} */ -export const assignAttributes = function (elem, attrs, suspendLength, unitCheck) { - for (const [ key, value ] of Object.entries(attrs)) { +export const assignAttributes = (elem, attrs, suspendLength, unitCheck) => { + for (const [key, value] of Object.entries(attrs)) { const ns = (key.substr(0, 4) === 'xml:' ? NS.XML - : key.substr(0, 6) === 'xlink:' ? NS.XLINK : null); - if (isNullish(value)) { + : key.substr(0, 6) === 'xlink:' ? NS.XLINK : null) + if (value === undefined) { 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. @@ -1239,7 +1085,7 @@ export const assignAttributes = function (elem, attrs, suspendLength, unitCheck) * @param {Element} element - DOM element to clean up * @returns {void} */ -export const cleanupElement = function (element) { +export const cleanupElement = (element) => { const defaults = { 'fill-opacity': 1, 'stop-opacity': 1, @@ -1252,20 +1098,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. @@ -1273,15 +1119,15 @@ export const cleanupElement = function (element) { * @param {Float} value * @returns {Integer} */ -export const snapToGrid = function (value) { - const unit = editorContext_.getBaseUnit(); - let stepSize = editorContext_.getSnappingStep(); +export const snapToGrid = (value) => { + 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. @@ -1289,11 +1135,11 @@ export const snapToGrid = function (value) { * @param {Element} img - The DOM element to prevent the click on * @returns {void} */ -export const preventClickDefault = function (img) { - img.addEventListener('click', function (e) { - e.preventDefault(); - }); -}; +export const preventClickDefault = (img) => { + img.addEventListener('click', (e) => { + e.preventDefault() + }) +} /** * @callback module:utilities.GetNextID @@ -1306,8 +1152,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. @@ -1321,28 +1167,27 @@ 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 = (parent, child, index = 0) => { + const doc = stringToHTML(child) 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 9bc76f66..d1c6a1eb 100644 --- a/web-dev-server.config.mjs +++ b/web-dev-server.config.mjs @@ -1,14 +1,49 @@ // 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' -const commonjs = fromRollup(rollupCommonjs); +const commonjs = fromRollup(rollupCommonjs) +const html = fromRollup(rollupHtml) export default { + mimeTypes: { + // serve imported html files as js + 'src/editor/panels/*.html': 'js', + 'src/editor/templates/*.html': 'js', + 'src/editor/dialogs/*.html': 'js', + 'src/editor/extensions/*/*.html': 'js', + 'instrumented/editor/panels/*.html': 'js', + 'instrumented/editor/templates/*.html': 'js', + 'instrumented/editor/dialogs/*.html': 'js', + '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' + ] + }), commonjs({ - exclude: [ 'src', 'dist', 'instrumented' ] + // explicitely list packages to increase performance + include: [ + '**/node_modules/rgbcolor/**/*', + '**/node_modules/raf/**/*', + '**/node_modules/font-family-papandreou/**/*', + '**/node_modules/svgpath/**/*', + '**/node_modules/cssesc/**/*', + '**/node_modules/core-js/**/*', + '**/node_modules/performance-now/**/*' + ] }) ] -}; +}