1- /*! JointJS v3.6.3 (2022-11-28 ) - JavaScript diagramming library
1+ /*! JointJS v3.6.4 (2022-12-08 ) - JavaScript diagramming library
22
33
44This Source Code Form is subject to the terms of the Mozilla Public
@@ -3134,12 +3134,25 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
31343134 var rect = Rect;
31353135
31363136 function parsePoints(svgString) {
3137- svgString = svgString.trim();
3138- if (svgString === '') { return []; }
3137+
3138+ // Step 1: Discard surrounding spaces
3139+ var trimmedString = svgString.trim();
3140+ if (trimmedString === '') { return []; }
3141+
31393142 var points = [];
3140- var coords = svgString.split(/\s*,\s*|\s+/);
3141- var n = coords.length;
3142- for (var i = 0; i < n; i += 2) {
3143+
3144+ // Step 2: Split at commas (+ their surrounding spaces) or at multiple spaces
3145+ // ReDoS mitigation: Have an anchor at the beginning of each alternation
3146+ // Note: This doesn't simplify double (or more) commas - causes empty coords
3147+ // This regex is used by `split()`, so it doesn't need to use /g
3148+ var coords = trimmedString.split(/\b\s*,\s*|,\s*|\s+/);
3149+
3150+ var numCoords = coords.length;
3151+ for (var i = 0; i < numCoords; i += 2) {
3152+ // Step 3: Convert each coord to number
3153+ // Note: If the coord cannot be converted to a number, it will be `NaN`
3154+ // Note: If the coord is empty ("", e.g. from ",," input), it will be `0`
3155+ // Note: If we end up with an odd number of coords, the last point's second coord will be `NaN`
31433156 points.push({ x: +coords[i], y: +coords[i + 1] });
31443157 }
31453158 return points;
@@ -9342,37 +9355,61 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
93429355 };
93439356 };
93449357
9345- V.transformRegex = /(\w+)\(([^,)]+),?([^)]+)?\)/gi;
9358+ // Note: This regex allows multiple commas as separator which is incorrect in SVG
9359+ // This regex is used by `split()`, so it doesn't need to use /g
93469360 V.transformSeparatorRegex = /[ ,]+/;
9347- V.transformationListRegex = /^(\w+)\((.*)\)/;
9361+ // Note: All following regexes are more restrictive than SVG specification
9362+ // ReDoS mitigation: Use an anchor at the beginning of the match
9363+ // ReDoS mitigation: Avoid backtracking (uses `[^()]+` instead of `.*?`)
9364+ // ReDoS mitigation: Don't match initial `(` inside repeated part
9365+ // The following regex needs to use /g (= cannot use capturing groups)
9366+ V.transformRegex = /\b\w+\([^()]+\)/g;
9367+ // The following regexes need to use capturing groups (= cannot use /g)
9368+ V.transformFunctionRegex = /\b(\w+)\(([^()]+)\)/;
9369+ V.transformTranslateRegex = /\btranslate\(([^()]+)\)/;
9370+ V.transformRotateRegex = /\brotate\(([^()]+)\)/;
9371+ V.transformScaleRegex = /\bscale\(([^()]+)\)/;
93489372
93499373 V.transformStringToMatrix = function(transform) {
93509374
9375+ // Initialize result matrix as identity matrix
93519376 var transformationMatrix = V.createSVGMatrix();
9352- var matches = transform && transform.match(V.transformRegex);
9353- if (!matches) {
9377+
9378+ // Note: Multiple transform functions are allowed in `transform` string
9379+ // `match()` returns `null` if none found
9380+ var transformMatches = transform && transform.match(V.transformRegex);
9381+ if (!transformMatches) {
9382+ // Return identity matrix
93549383 return transformationMatrix;
93559384 }
93569385
9357- for ( var i = 0, n = matches .length; i < n; i++) {
9358- var transformationString = matches[i];
9386+ var numMatches = transformMatches .length;
9387+ for ( var i = 0; i < numMatches; i++) {
93599388
9360- var transformationMatch = transformationString.match(V.transformationListRegex);
9361- if (transformationMatch) {
9362- var sx, sy, tx, ty, angle;
9389+ var transformMatch = transformMatches[i];
9390+ // Use same regex as above, but with capturing groups
9391+ // `match()` returns values of capturing groups as `[1]`, `[2]`
9392+ var transformFunctionMatch = transformMatch.match(V.transformFunctionRegex);
9393+ if (transformFunctionMatch) {
9394+
9395+ var sx = (void 0), sy = (void 0), tx = (void 0), ty = (void 0), angle = (void 0);
93639396 var ctm = V.createSVGMatrix();
9364- var args = transformationMatch[2].split(V.transformSeparatorRegex);
9365- switch (transformationMatch[1].toLowerCase()) {
9397+ var transformFunction = transformFunctionMatch[1].toLowerCase();
9398+ var args = transformFunctionMatch[2].split(V.transformSeparatorRegex);
9399+ switch (transformFunction) {
9400+
93669401 case 'scale':
93679402 sx = parseFloat(args[0]);
93689403 sy = (args[1] === undefined) ? sx : parseFloat(args[1]);
93699404 ctm = ctm.scaleNonUniform(sx, sy);
93709405 break;
9406+
93719407 case 'translate':
93729408 tx = parseFloat(args[0]);
93739409 ty = parseFloat(args[1]);
93749410 ctm = ctm.translate(tx, ty);
93759411 break;
9412+
93769413 case 'rotate':
93779414 angle = parseFloat(args[0]);
93789415 tx = parseFloat(args[1]) || 0;
@@ -9383,14 +9420,17 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
93839420 ctm = ctm.rotate(angle);
93849421 }
93859422 break;
9423+
93869424 case 'skewx':
93879425 angle = parseFloat(args[0]);
93889426 ctm = ctm.skewX(angle);
93899427 break;
9428+
93909429 case 'skewy':
93919430 angle = parseFloat(args[0]);
93929431 ctm = ctm.skewY(angle);
93939432 break;
9433+
93949434 case 'matrix':
93959435 ctm.a = parseFloat(args[0]);
93969436 ctm.b = parseFloat(args[1]);
@@ -9399,10 +9439,12 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
93999439 ctm.e = parseFloat(args[4]);
94009440 ctm.f = parseFloat(args[5]);
94019441 break;
9442+
94029443 default:
94039444 continue;
94049445 }
94059446
9447+ // Multiply current transformation into result matrix
94069448 transformationMatrix = transformationMatrix.multiply(ctm);
94079449 }
94089450
@@ -9431,16 +9473,21 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
94319473
94329474 var separator = V.transformSeparatorRegex;
94339475
9434- // Allow reading transform string with a single matrix
9476+ // Special handling for ` transform` with one or more matrix functions
94359477 if (transform.trim().indexOf('matrix') >= 0) {
94369478
9479+ // Convert EVERYTHING in `transform` string to a matrix
9480+ // Will combine ALL matrixes * ALL translates * ALL scales * ALL rotates
9481+ // Note: In non-matrix case, we only take first one of each (if any)
94379482 var matrix = V.transformStringToMatrix(transform);
94389483 var decomposedMatrix = V.decomposeMatrix(matrix);
94399484
9485+ // Extract `translate`, `scale`, `rotate` from matrix
94409486 translate = [decomposedMatrix.translateX, decomposedMatrix.translateY];
94419487 scale = [decomposedMatrix.scaleX, decomposedMatrix.scaleY];
94429488 rotate = [decomposedMatrix.rotation];
94439489
9490+ // Rewrite `transform` string in `translate scale rotate` format
94449491 var transformations = [];
94459492 if (translate[0] !== 0 || translate[1] !== 0) {
94469493 transformations.push('translate(' + translate + ')');
@@ -9455,15 +9502,18 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
94559502
94569503 } else {
94579504
9458- var translateMatch = transform.match(/translate\((.*?)\)/);
9505+ // Extract `translate`, `rotate`, `scale` functions from `transform` string
9506+ // Note: We only detect the first match of each (if any)
9507+ // `match()` returns value of capturing group as `[1]`
9508+ var translateMatch = transform.match(V.transformTranslateRegex);
94599509 if (translateMatch) {
94609510 translate = translateMatch[1].split(separator);
94619511 }
9462- var rotateMatch = transform.match(/rotate\((.*?)\)/ );
9512+ var rotateMatch = transform.match(V.transformRotateRegex );
94639513 if (rotateMatch) {
94649514 rotate = rotateMatch[1].split(separator);
94659515 }
9466- var scaleMatch = transform.match(/scale\((.*?)\)/ );
9516+ var scaleMatch = transform.match(V.transformScaleRegex );
94679517 if (scaleMatch) {
94689518 scale = scaleMatch[1].split(separator);
94699519 }
@@ -29899,7 +29949,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
2989929949
2990029950 if (evt.button === 2) {
2990129951 this.contextMenuFired = true;
29902- this.contextMenuTrigger($.Event(evt, { type: 'contextmenu', data: evt.data }));
29952+ var contextmenuEvt = $.Event(evt, { type: 'contextmenu', data: evt.data });
29953+ this.contextMenuTrigger(contextmenuEvt);
2990329954 } else {
2990429955 var view = this.findView(evt.target);
2990529956
@@ -30162,12 +30213,21 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
3016230213
3016330214 onmagnet: function(evt) {
3016430215
30165- this.magnetEvent(evt, function(view, evt, _, x, y) {
30166- view.onmagnet(evt, x, y);
30167- });
30216+ if (evt.button === 2) {
30217+ this.contextMenuFired = true;
30218+ this.magnetContextMenuFired = true;
30219+ var contextmenuEvt = $.Event(evt, { type: 'contextmenu', data: evt.data });
30220+ this.magnetContextMenuTrigger(contextmenuEvt);
30221+ if (contextmenuEvt.isPropagationStopped()) {
30222+ evt.stopPropagation();
30223+ }
30224+ } else {
30225+ this.magnetEvent(evt, function(view, evt, _, x, y) {
30226+ view.onmagnet(evt, x, y);
30227+ });
30228+ }
3016830229 },
3016930230
30170-
3017130231 magnetpointerdblclick: function(evt) {
3017230232
3017330233 this.magnetEvent(evt, function(view, evt, magnet, x, y) {
@@ -30176,8 +30236,17 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
3017630236 },
3017730237
3017830238 magnetcontextmenu: function(evt) {
30179-
3018030239 if (this.options.preventContextMenu) { evt.preventDefault(); }
30240+
30241+ if (this.magnetContextMenuFired) {
30242+ this.magnetContextMenuFired = false;
30243+ return;
30244+ }
30245+
30246+ this.magnetContextMenuTrigger(evt);
30247+ },
30248+
30249+ magnetContextMenuTrigger: function(evt) {
3018130250 this.magnetEvent(evt, function(view, evt, magnet, x, y) {
3018230251 view.magnetcontextmenu(evt, magnet, x, y);
3018330252 });
@@ -32772,7 +32841,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
3277232841 Control: Control
3277332842 });
3277432843
32775- var version = "3.6.3 ";
32844+ var version = "3.6.4 ";
3277632845
3277732846 var Vectorizer = V;
3277832847 var layout = { PortLabel: PortLabel, Port: Port };
0 commit comments