- Linting (ESLint): Lint per latest ash-nazg (e.g., named capture)

- Linting (ESLint): Add HTML files to linting and add devDeps for new ash-nazg
- npm: Update devDeps
This commit is contained in:
Brett Zamir
2019-07-02 12:21:21 +08:00
parent af290bd743
commit e4231aeb10
30 changed files with 313 additions and 267 deletions

View File

@@ -1,4 +1,4 @@
/* eslint-disable new-cap, class-methods-use-this */
/* eslint-disable new-cap, class-methods-use-this, prefer-named-capture-group */
// Todo: Compare with latest canvg (add any improvements of ours) and add full JSDocs (denoting links to standard APIs and which are custom): https://github.com/canvg/canvg
/**
* canvg.js - Javascript SVG parser and renderer on Canvas
@@ -13,7 +13,7 @@ import {canvasRGBA} from '../external/stackblur-canvas/dist/stackblur-es.js';
/**
* Whether a value is `null` or `undefined`.
* @param {Any} val
* @param {any} val
* @returns {boolean}
*/
const isNullish = (val) => {

View File

@@ -154,21 +154,21 @@ const simpleColors = {
// array of color definition objects
const colorDefs = [
{
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
re: /^rgb\((?<r>\d{1,3}),\s*(?<g>\d{1,3}),\s*(?<b>\d{1,3})\)$/,
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
process (_, ...bits) {
return bits.map((b) => parseInt(b));
}
},
{
re: /^(\w{2})(\w{2})(\w{2})$/,
re: /^(?<r>\w{2})(?<g>\w{2})(?<b>\w{2})$/,
example: ['#00ff00', '336699'],
process (_, ...bits) {
return bits.map((b) => parseInt(b, 16));
}
},
{
re: /^(\w{1})(\w{1})(\w{1})$/,
re: /^(?<r>\w{1})(?<g>\w{1})(?<b>\w{1})$/,
example: ['#fb0', 'f0f'],
process (_, ...bits) {
return bits.map((b) => parseInt(b + b, 16));
@@ -210,7 +210,7 @@ export default class RGBColor {
Object.assign(this, {r, g, b});
this.ok = true;
}
}, this);
});
// validate/cleanup values
this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);

View File

@@ -51,9 +51,8 @@ export const init = function (editorContext) {
/**
* Applies coordinate changes to an element based on the given matrix.
* @function module:coords.remapElement
* @implements {module:path.EditorContext#remapElement}
* @returns {void}
* @name module:coords.remapElement
* @type {module:path.EditorContext#remapElement}
*/
export const remapElement = function (selected, changes, m) {
const remap = function (x, y) { return transformPoint(x, y, m); },

View File

@@ -96,6 +96,8 @@ const framePath = '/editor/xdomain-svg-editor-es.html?extensions=ext-xdomain-mes
const iframe = $('<iframe width="900px" height="600px" id="svgedit"></iframe>');
iframe[0].src = frameBase + framePath +
(location.href.includes('?')
// ? location.href.replace(/\?(?<search>.*)$/, '&$<search>')
// eslint-disable-next-line prefer-named-capture-group
? location.href.replace(/\?(.*)$/, '&$1')
: ''); // Append arguments to this file onto the iframe

View File

@@ -12,7 +12,7 @@ let cbid = 0;
*/
/**
* @callback module:EmbeddedSVGEdit.CallbackSetGetter
* @param {...Any} args Signature dependent on the function
* @param {...any} args Signature dependent on the function
* @returns {module:EmbeddedSVGEdit.CallbackSetter}
*/

View File

@@ -65,11 +65,11 @@ export default {
function getLinked (elem, attr) {
const str = elem.getAttribute(attr);
if (!str) { return null; }
const m = str.match(/\(#(.*)\)/);
if (!m || m.length !== 2) {
const m = str.match(/\(#(?<id>.+)\)/);
if (!m || !m.groups.id) {
return null;
}
return svgCanvas.getElem(m[1]);
return svgCanvas.getElem(m.groups.id);
}
/**

View File

@@ -86,11 +86,11 @@ export default {
function getLinked (elem, attr) {
const str = elem.getAttribute(attr);
if (!str) { return null; }
const m = str.match(/\(#(.*)\)/);
if (!m || m.length !== 2) {
const m = str.match(/\(#(?<id>.+)\)/);
if (!m || !m.groups.id) {
return null;
}
return svgCanvas.getElem(m[1]);
return svgCanvas.getElem(m.groups.id);
}
/**
@@ -254,7 +254,7 @@ export default {
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; }
if (elem.tagName !== 'line') { return elem; }
// Convert to polyline to accept mid-arrow

View File

@@ -70,11 +70,11 @@ export default {
if (!elem) { return null; }
const str = elem.getAttribute(attr);
if (!str) { return null; }
const m = str.match(/\(#(.*)\)/);
if (!m || m.length !== 2) {
const m = str.match(/\(#(?<id>.+)\)/);
if (!m || !m.groups.id) {
return null;
}
return svgCanvas.getElem(m[1]);
return svgCanvas.getElem(m.groups.id);
}
/**

View File

@@ -56,8 +56,8 @@ export default {
val = val ? 'storagePrompt=' + val : '';
const loc = top.location; // Allow this to work with the embedded editor as well
if (loc.href.includes('storagePrompt=')) {
loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) {
return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''));
loc.href = loc.href.replace(/(?<sep>[&?])storagePrompt=[^&]*(?<amp>&?)/, function (n0, sep, amp) {
return (val ? sep : '') + val + (!val && amp ? sep : (amp || ''));
});
} else {
loc.href += (loc.href.includes('?') ? '&' : '?') + val;

View File

@@ -39,9 +39,9 @@ function addScriptAtts (script, atts) {
/**
* @function module:importModule.importSetGlobalDefault
* @param {string|GenericArray<Any>} url
* @param {string|GenericArray<any>} url
* @param {module:importModule.ImportConfig} config
* @returns {Promise<Any>} The value to which it resolves depends on the export of the targeted module.
* @returns {Promise<any>} The value to which it resolves depends on the export of the targeted module.
*/
export function importSetGlobalDefault (url, config) {
return importSetGlobal(url, {...config, returnDefault: true});
@@ -118,7 +118,7 @@ export function importScript (url, atts = {}) {
* @param {PlainObject} [atts={}]
* @param {PlainObject} opts
* @param {boolean} [opts.returnDefault=false} = {}]
* @returns {Promise<Any>} Resolves to value of loading module or rejects with
* @returns {Promise<any>} Resolves to value of loading module or rejects with
* `Error` upon a script loading error.
*/
export function importModule (url, atts = {}, {returnDefault = false} = {}) {

View File

@@ -32,7 +32,7 @@ function toFixedNumeric (value, precision) {
/**
* Whether a value is `null` or `undefined`.
* @param {Any} val
* @param {any} val
* @returns {boolean}
*/
const isNullish = (val) => {

View File

@@ -1484,12 +1484,12 @@ export const reorientGrads = function (elem, m) {
const pt2 = transformPoint(x2, y2, m);
// Convert back to BB points
const gCoords = {};
gCoords.x1 = (pt1.x - bb.x) / bb.width;
gCoords.y1 = (pt1.y - bb.y) / bb.height;
gCoords.x2 = (pt2.x - bb.x) / bb.width;
gCoords.y2 = (pt2.y - bb.y) / bb.height;
const gCoords = {
x1: (pt1.x - bb.x) / bb.width,
y1: (pt1.y - bb.y) / bb.height,
x2: (pt2.x - bb.x) / bb.width,
y2: (pt2.y - bb.y) / bb.height
};
const newgrad = grad.cloneNode(true);
$(newgrad).attr(gCoords);
@@ -1632,6 +1632,7 @@ export const convertPath = function (pth, toRel) {
}
d += pathDSegment(letter, [[x1, y1], [x, y]]);
break;
// eslint-disable-next-line sonarjs/no-duplicated-branches
case 10: // absolute elliptical arc (A)
x -= curx;
y -= cury;

View File

@@ -3,6 +3,6 @@
// We only need to replace the first instance
location.href = location.href
.replace(/(xdomain-)?svg-editor-es\.html/, 'svg-editor.html')
.replace(/(?:xdomain-)?svg-editor-es\.html/, 'svg-editor.html')
.replace('openclipart-es.html', 'openclipart.html')
.replace('imagelib/index-es.html', 'imagelib/index.html');

View File

@@ -166,7 +166,7 @@ export const sanitizeSvg = function (node) {
case 'transform':
case 'gradientTransform':
case 'patternTransform': {
const val = attr.value.replace(/(\d)-/g, '$1 -');
const val = attr.value.replace(/(?<digit>\d)-/g, '$<digit> -');
node.setAttribute(attrName, val);
break;
}

View File

@@ -495,7 +495,7 @@ editor.setConfig = function (opts, cfgCfg) {
*
* @param {module:SVGEditor.Config|module:SVGEditor.Prefs} cfgObj
* @param {string} key
* @param {Any} val See {@link module:SVGEditor.Config} or {@link module:SVGEditor.Prefs}
* @param {any} val See {@link module:SVGEditor.Config} or {@link module:SVGEditor.Prefs}
* @returns {void}
*/
function extendOrAdd (cfgObj, key, val) {
@@ -757,7 +757,7 @@ editor.init = function () {
qstr = $.param.querystring();
if (!src) { // urldata.source may have been null if it ended with '='
if (qstr.includes('source=data:')) {
src = qstr.match(/source=(data:[^&]*)/)[1];
({src} = qstr.match(/source=(?<src>data:[^&]*)/).groups);
}
}
if (src) {
@@ -820,7 +820,7 @@ editor.init = function () {
try {
await Promise.all(
curConfig.extensions.map(async (extname) => {
const extName = extname.match(/^ext-(.+)\.js/);
const {extName} = extname.match(/^ext-(?<extName>.+)\.js/).groups;
if (!extName) { // Ensure URL cannot specify some other unintended file in the extPath
return undefined;
}
@@ -838,9 +838,9 @@ editor.init = function () {
* @type {module:SVGEditor.ExtensionObject}
*/
const imported = await importSetGlobalDefault(url, {
global: 'svgEditorExtension_' + extName[1].replace(/-/g, '_')
global: 'svgEditorExtension_' + extName.replace(/-/g, '_')
});
const {name = extName[1], init} = imported;
const {name = extName, init} = imported;
const importLocale = getImportLocale({defaultLang: langParam, defaultName: name});
return editor.addExtension(name, (init && init.bind(editor)), {$, importLocale});
} catch (err) {
@@ -909,7 +909,7 @@ editor.init = function () {
* @type {string}
*/
const uaPrefix = (function () {
const regex = /^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/;
const regex = /^(?:Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/;
const someScript = document.getElementsByTagName('script')[0];
for (const prop in someScript.style) {
if (regex.test(prop)) {
@@ -2735,7 +2735,7 @@ editor.init = function () {
};
/**
* @implements {module:jQuerySpinButton.ValueCallback}
* @type {module:jQuerySpinButton.ValueCallback}
*/
const changeZoom = function (ctl) {
const zoomlevel = ctl.value / 100;
@@ -3581,21 +3581,21 @@ editor.init = function () {
$('#image_save_opts input').val([$.pref('img_save')]);
/**
* @implements {module:jQuerySpinButton.ValueCallback}
* @type {module:jQuerySpinButton.ValueCallback}
*/
const changeRectRadius = function (ctl) {
svgCanvas.setRectRadius(ctl.value);
};
/**
* @implements {module:jQuerySpinButton.ValueCallback}
* @type {module:jQuerySpinButton.ValueCallback}
*/
const changeFontSize = function (ctl) {
svgCanvas.setFontSize(ctl.value);
};
/**
* @implements {module:jQuerySpinButton.ValueCallback}
* @type {module:jQuerySpinButton.ValueCallback}
*/
const changeStrokeWidth = function (ctl) {
let val = ctl.value;
@@ -3606,7 +3606,7 @@ editor.init = function () {
};
/**
* @implements {module:jQuerySpinButton.ValueCallback}
* @type {module:jQuerySpinButton.ValueCallback}
*/
const changeRotationAngle = function (ctl) {
svgCanvas.setRotationAngle(ctl.value);
@@ -5456,8 +5456,7 @@ editor.init = function () {
$(window).bind('load resize', centerCanvas);
/**
* @implements {module:jQuerySpinButton.StepCallback}
* @returns {Float}
* @type {module:jQuerySpinButton.StepCallback}
*/
function stepFontSize (elem, step) {
const origVal = Number(elem.value);
@@ -5481,8 +5480,7 @@ editor.init = function () {
}
/**
* @implements {module:jQuerySpinButton.StepCallback}
* @returns {Float}
* @type {module:jQuerySpinButton.StepCallback}
*/
function stepZoom (elem, step) {
const origVal = Number(elem.value);
@@ -6519,7 +6517,7 @@ let extensionsAdded = false;
const messageQueue = [];
/**
* @param {PlainObject} info
* @param {Any} info.data
* @param {any} info.data
* @param {string} info.origin
* @fires module:svgcanvas.SvgCanvas#event:message
* @returns {void}

View File

@@ -228,9 +228,8 @@ canvas.current_drawing_ = new draw.Drawing(svgcontent, idprefix);
/**
* Returns the current Drawing.
* @function module:svgcanvas.SvgCanvas#getCurrentDrawing
* @implements {module:draw.DrawCanvasInit#getCurrentDrawing}
* @returns {module:draw.Drawing}
* @name module:svgcanvas.SvgCanvas#getCurrentDrawing
* @type {module:draw.DrawCanvasInit#getCurrentDrawing}
*/
const getCurrentDrawing = canvas.getCurrentDrawing = function () {
return canvas.current_drawing_;
@@ -315,9 +314,8 @@ const getJsonFromSvgElement = this.getJsonFromSvgElement = function (data) {
/**
* This should really be an intersection implementing all rather than a union.
* @function module:svgcanvas.SvgCanvas#addSVGElementFromJson
* @implements {module:utilities.EditorContext#addSVGElementFromJson|module:path.EditorContext#addSVGElementFromJson}
* @returns {Element} The new element
* @name module:svgcanvas.SvgCanvas#addSVGElementFromJson
* @type {module:utilities.EditorContext#addSVGElementFromJson|module:path.EditorContext#addSVGElementFromJson}
*/
const addSVGElementFromJson = this.addSVGElementFromJson = function (data) {
if (typeof data === 'string') return svgdoc.createTextNode(data);
@@ -370,8 +368,7 @@ canvas.hasMatrixTransform = hasMatrixTransform;
canvas.transformListToTransform = transformListToTransform;
/**
* @implements {module:utilities.EditorContext#getBaseUnit}
* @returns {string}
* @type {module:utilities.EditorContext#getBaseUnit}
*/
const getBaseUnit = () => { return curConfig.baseUnit; };
@@ -396,16 +393,14 @@ canvas.convertToNum = convertToNum;
/**
* This should really be an intersection implementing all rather than a union.
* @implements {module:draw.DrawCanvasInit#getSVGContent|module:utilities.EditorContext#getSVGContent}
* @returns {SVGSVGElement}
* @type {module:draw.DrawCanvasInit#getSVGContent|module:utilities.EditorContext#getSVGContent}
*/
const getSVGContent = () => { return svgcontent; };
/**
* Should really be an intersection with all needing to apply rather than a union.
* @function module:svgcanvas.SvgCanvas#getSelectedElements
* @implements {module:utilities.EditorContext#getSelectedElements|module:draw.DrawCanvasInit#getSelectedElements|module:path.EditorContext#getSelectedElements}
* @returns {Element[]} the array with selected DOM elements
* @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;
@@ -415,8 +410,7 @@ const {pathActions} = pathModule;
/**
* This should actually be an intersection as all interfaces should be met.
* @implements {module:utilities.EditorContext#getSVGRoot|module:recalculate.EditorContext#getSVGRoot|module:coords.EditorContext#getSVGRoot|module:path.EditorContext#getSVGRoot}
* @returns {SVGSVGElement}
* @type {module:utilities.EditorContext#getSVGRoot|module:recalculate.EditorContext#getSVGRoot|module:coords.EditorContext#getSVGRoot|module:path.EditorContext#getSVGRoot}
*/
const getSVGRoot = () => svgroot;
@@ -452,8 +446,7 @@ this.cleanupElement = cleanupElement;
/**
* This should actually be an intersection not a union as all should apply.
* @implements {module:coords.EditorContext#getGridSnapping|module:path.EditorContext#getGridSnapping}
* @returns {boolean}
* @type {module:coords.EditorContext#getGridSnapping|module:path.EditorContext#getGridSnapping}
*/
const getGridSnapping = () => { return curConfig.gridSnapping; };
@@ -559,8 +552,8 @@ const undoMgr = canvas.undoMgr = new UndoManager({
/**
* This should really be an intersection applying to all types rather than a union.
* @function module:svgcanvas~addCommandToHistory
* @implements {module:path.EditorContext#addCommandToHistory|module:draw.DrawCanvasInit#addCommandToHistory}
* @name module:svgcanvas~addCommandToHistory
* @type {module:path.EditorContext#addCommandToHistory|module:draw.DrawCanvasInit#addCommandToHistory}
*/
const addCommandToHistory = function (cmd) {
canvas.undoMgr.addCommandToHistory(cmd);
@@ -568,17 +561,15 @@ const addCommandToHistory = function (cmd) {
/**
* This should really be an intersection applying to all types rather than a union.
* @function module:svgcanvas.SvgCanvas#getZoom
* @implements {module:path.EditorContext#getCurrentZoom|module:select.SVGFactory#getCurrentZoom}
* @returns {Float} The current zoom level
* @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`
* @function module:svgcanvas.SvgCanvas#round
* @implements {module:path.EditorContext#round}
* @returns {Float} Rounded value to nearest value based on `currentZoom`
* @name module:svgcanvas.SvgCanvas#round
* @type {module:path.EditorContext#round}
*/
const round = this.round = function (val) {
return parseInt(val * currentZoom) / currentZoom;
@@ -605,18 +596,16 @@ selectInit(
const selectorManager = this.selectorManager = getSelectorManager();
/**
* @function module:svgcanvas.SvgCanvas#getNextId
* @implements {module:path.EditorContext#getNextId}
* @returns {string}
* @name module:svgcanvas.SvgCanvas#getNextId
* @type {module:path.EditorContext#getNextId}
*/
const getNextId = canvas.getNextId = function () {
return getCurrentDrawing().getNextId();
};
/**
* @function module:svgcanvas.SvgCanvas#getId
* @implements {module:path.EditorContext#getId}
* @returns {string}
* @name module:svgcanvas.SvgCanvas#getId
* @type {module:path.EditorContext#getId}
*/
const getId = canvas.getId = function () {
return getCurrentDrawing().getId();
@@ -624,11 +613,8 @@ const getId = canvas.getId = function () {
/**
* The "implements" should really be an intersection applying to all types rather than a union.
* @function module:svgcanvas.SvgCanvas#call
* @implements {module:draw.DrawCanvasInit#call|module:path.EditorContext#call}
* @param {"selected"|"changed"|"contextset"|"pointsAdded"|"extension_added"|"extensions_added"|"message"|"transition"|"zoomed"|"updateCanvas"|"zoomDone"|"saved"|"exported"|"exportedPDF"|"setnonce"|"unsetnonce"|"cleared"} ev - String with the event name
* @param {module:svgcanvas.SvgCanvas#event:GenericCanvasEvent} arg - Argument to pass through to the callback function.
* @returns {module:svgcanvas.EventHandlerReturn|void}
* @name module:svgcanvas.SvgCanvas#call
* @type {module:draw.DrawCanvasInit#call|module:path.EditorContext#call}
*/
const call = function (ev, arg) {
if (events[ev]) {
@@ -640,8 +626,8 @@ const call = function (ev, arg) {
/**
* Clears the selection. The 'selected' handler is then optionally called.
* This should really be an intersection applying to all types rather than a union.
* @function module:svgcanvas.SvgCanvas#clearSelection
* @implements {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection}
* @name module:svgcanvas.SvgCanvas#clearSelection
* @type {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection}
* @fires module:svgcanvas.SvgCanvas#event:selected
*/
const clearSelection = this.clearSelection = function (noCall) {
@@ -658,10 +644,9 @@ const clearSelection = this.clearSelection = function (noCall) {
/**
* Adds a list of elements to the selection. The 'selected' handler is then called.
* @function module:svgcanvas.SvgCanvas#addToSelection
* @implements {module:path.EditorContext#addToSelection}
* @name module:svgcanvas.SvgCanvas#addToSelection
* @type {module:path.EditorContext#addToSelection}
* @fires module:svgcanvas.SvgCanvas#event:selected
* @returns {void}
*/
const addToSelection = this.addToSelection = function (elemsToAdd, showGrips) {
if (!elemsToAdd.length) { return; }
@@ -730,17 +715,15 @@ const addToSelection = this.addToSelection = function (elemsToAdd, showGrips) {
};
/**
* @implements {module:path.EditorContext#getOpacity}
* @returns {Float}
* @type {module:path.EditorContext#getOpacity}
*/
const getOpacity = function () {
return curShape.opacity;
};
/**
* @function module:svgcanvas.SvgCanvas#getMouseTarget
* @implements {module:path.EditorContext#getMouseTarget}
* @returns {Element} DOM element we want
* @name module:svgcanvas.SvgCanvas#getMouseTarget
* @type {module:path.EditorContext#getMouseTarget}
*/
const getMouseTarget = this.getMouseTarget = function (evt) {
if (isNullish(evt)) {
@@ -803,7 +786,7 @@ const getMouseTarget = this.getMouseTarget = function (evt) {
*/
canvas.pathActions = pathActions;
/**
* @implements {module:path.EditorContext#resetD}
* @type {module:path.EditorContext#resetD}
*/
function resetD (p) {
p.setAttribute('d', pathActions.convertPath(p));
@@ -1386,7 +1369,7 @@ canvas.call = call;
*/
/**
* @typedef {PlainObject} module:svgcanvas.Message
* @property {Any} data The data
* @property {any} data The data
* @property {string} origin The origin
*/
/**
@@ -4549,9 +4532,9 @@ this.setSvgString = function (xmlString, preventUndo) {
if (val) {
if (val.startsWith('data:')) {
// Check if an SVG-edit data URI
const m = val.match(/svgedit_url=(.*?);/);
const m = val.match(/svgedit_url=(?<url>.*?);/);
if (m) {
const url = decodeURIComponent(m[1]);
const url = decodeURIComponent(m.groups.url);
$(new Image()).load(function () {
image.setAttributeNS(NS.XLINK, 'xlink:href', url);
}).attr('src', url);

View File

@@ -145,19 +145,20 @@ export class SVGTransformList { // eslint-disable-line no-shadow
if (!str) { return; }
// TODO: Add skew support in future
const re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/;
const re = /\s*(?<xform>(?:scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/;
let m = true;
while (m) {
m = str.match(re);
str = str.replace(re, '');
if (m && m[1]) {
const x = m[1];
const bits = x.split(/\s*\(/);
const name = bits[0];
const valBits = bits[1].match(/\s*(.*?)\s*\)/);
valBits[1] = valBits[1].replace(/(\d)-/g, '$1 -');
const valArr = valBits[1].split(/[, ]+/);
const letters = 'abcdef'.split('');
if (m && m.groups.xform) {
const x = m.groups.xform;
const [name, bits] = x.split(/\s*\(/);
const valBits = bits.match(/\s*(?<nonWhitespace>.*?)\s*\)/);
valBits.groups.nonWhitespace = valBits.groups.nonWhitespace.replace(
/(?<digit>\d)-/g, '$<digit> -'
);
const valArr = valBits.groups.nonWhitespace.split(/[, ]+/);
const letters = [...'abcdef'];
const mtx = svgroot.createSVGMatrix();
Object.values(valArr).forEach(function (item, i) {
valArr[i] = parseFloat(item);

View File

@@ -13,12 +13,12 @@
/**
* This should only be used when the return result from a callback
* is not known as to type.
* @typedef {Any} ArbitraryCallbackResult
* @typedef {any} ArbitraryCallbackResult
*/
/**
* @callback GenericCallback
* @param {...Any} args Signature dependent on the function
* @param {...any} args Signature dependent on the function
* @returns {ArbitraryCallbackResult} Return dependent on the function
*/

View File

@@ -110,7 +110,7 @@ export const init = function (editorContext) {
* @todo This might be needed in other places `parseFromString` is used even without LGTM flagging
*/
export const dropXMLInteralSubset = (str) => {
return str.replace(/(<!DOCTYPE\s+\w*\s*\[).*(\?\]>)/, '$1$2');
return str.replace(/(?<doctypeOpen><!DOCTYPE\s+\w*\s*\[).*(?<doctypeClose>\?\]>)/, '$<doctypeOpen>$<doctypeClose>');
};
/**
@@ -265,9 +265,9 @@ export const dataURLToObjectURL = function (dataurl) {
if (typeof Uint8Array === 'undefined' || typeof Blob === 'undefined' || typeof URL === 'undefined' || !URL.createObjectURL) {
return '';
}
const arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]);
const [prefix, suffix] = dataurl.split(','),
{groups: {mime}} = prefix.match(/:(?<mime>.*?);/),
bstr = atob(suffix);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
@@ -330,6 +330,7 @@ export const convertToXMLReferences = function (input) {
*/
export const text2xml = function (sXML) {
if (sXML.includes('<svg:svg')) {
// eslint-disable-next-line prefer-named-capture-group
sXML = sXML.replace(/<(\/?)svg:/g, '<$1').replace('xmlns:svg', 'xmlns');
}
@@ -651,11 +652,13 @@ export const getBBox = function (elem) {
// have a featured detection for correct 'use' behavior?
// ——————————
if (!isWebkit()) {
const bb = {};
bb.width = ret.width;
bb.height = ret.height;
bb.x = ret.x + parseFloat(selected.getAttribute('x') || 0);
bb.y = ret.y + parseFloat(selected.getAttribute('y') || 0);
const {x, y, width, height} = ret;
const bb = {
width,
height,
x: x + parseFloat(selected.getAttribute('x') || 0),
y: y + parseFloat(selected.getAttribute('y') || 0)
};
ret = bb;
}
} else if (visElemsArr.includes(elname)) {
@@ -1369,7 +1372,7 @@ export const copyElem = function (el, getNextId) {
/**
* Whether a value is `null` or `undefined`.
* @param {Any} val
* @param {any} val
* @returns {boolean}
*/
export const isNullish = (val) => {