@elyra/canvas 12.13.0 → 12.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/canvas-controller-8e2bb291.js +2 -0
  2. package/dist/canvas-controller-8e2bb291.js.map +1 -0
  3. package/dist/canvas-controller-bd0d8d59.js +2 -0
  4. package/dist/canvas-controller-bd0d8d59.js.map +1 -0
  5. package/dist/common-canvas-69fe4a67.js +2 -0
  6. package/dist/common-canvas-69fe4a67.js.map +1 -0
  7. package/dist/common-canvas-f5e4af65.js +2 -0
  8. package/dist/common-canvas-f5e4af65.js.map +1 -0
  9. package/dist/common-canvas.es.js +1 -1
  10. package/dist/common-canvas.js +1 -1
  11. package/dist/common-properties-40648163.js +2 -0
  12. package/dist/common-properties-40648163.js.map +1 -0
  13. package/dist/common-properties-6d839df1.js +2 -0
  14. package/dist/common-properties-6d839df1.js.map +1 -0
  15. package/dist/{flexible-table-f88dfef1.js → flexible-table-d3598aa8.js} +1 -1
  16. package/dist/{flexible-table-f88dfef1.js.map → flexible-table-d3598aa8.js.map} +1 -1
  17. package/dist/{flexible-table-b31e92b8.js → flexible-table-fe7fbc13.js} +1 -1
  18. package/dist/{flexible-table-b31e92b8.js.map → flexible-table-fe7fbc13.js.map} +1 -1
  19. package/dist/{index-b6f098b8.js → index-669f95a7.js} +2 -2
  20. package/dist/{index-b6f098b8.js.map → index-669f95a7.js.map} +1 -1
  21. package/dist/{index-f44d40bc.js → index-6d3404e1.js} +2 -2
  22. package/dist/{index-f44d40bc.js.map → index-6d3404e1.js.map} +1 -1
  23. package/dist/lib/canvas-controller.es.js +1 -1
  24. package/dist/lib/canvas-controller.js +1 -1
  25. package/dist/lib/canvas.es.js +1 -1
  26. package/dist/lib/canvas.js +1 -1
  27. package/dist/lib/properties/field-picker.es.js +1 -1
  28. package/dist/lib/properties/field-picker.js +1 -1
  29. package/dist/lib/properties/flexible-table.es.js +1 -1
  30. package/dist/lib/properties/flexible-table.js +1 -1
  31. package/dist/lib/properties.es.js +1 -1
  32. package/dist/lib/properties.js +1 -1
  33. package/dist/lib/tooltip.es.js +1 -1
  34. package/dist/lib/tooltip.es.js.map +1 -1
  35. package/dist/lib/tooltip.js +1 -1
  36. package/dist/lib/tooltip.js.map +1 -1
  37. package/dist/styles/common-canvas.min.css +1 -1
  38. package/dist/styles/common-canvas.min.css.map +1 -1
  39. package/dist/toolbar-29ec7983.js +2 -0
  40. package/dist/toolbar-29ec7983.js.map +1 -0
  41. package/dist/toolbar-3f4b173f.js +2 -0
  42. package/dist/toolbar-3f4b173f.js.map +1 -0
  43. package/locales/common-canvas/locales/en.json +15 -2
  44. package/locales/common-canvas/locales/eo.json +14 -1
  45. package/package.json +2 -1
  46. package/src/common-canvas/canvas-controller.js +17 -1
  47. package/src/common-canvas/cc-bottom-panel.jsx +37 -21
  48. package/src/common-canvas/cc-central-items.jsx +1 -1
  49. package/src/common-canvas/cc-contents.jsx +10 -0
  50. package/src/common-canvas/cc-text-toolbar.jsx +141 -0
  51. package/src/common-canvas/cc-toolbar.jsx +8 -6
  52. package/src/common-canvas/common-canvas.scss +48 -3
  53. package/src/common-canvas/svg-canvas-d3.scss +159 -16
  54. package/src/common-canvas/svg-canvas-renderer.js +204 -26
  55. package/src/common-canvas/svg-canvas-utils-markdown.js +515 -0
  56. package/src/common-properties/components/control-item/control-item.scss +1 -1
  57. package/src/common-properties/components/flexible-table/flexible-table.scss +1 -1
  58. package/src/common-properties/controls/checkbox/checkbox.jsx +1 -1
  59. package/src/common-properties/controls/checkboxset/checkboxset.jsx +36 -11
  60. package/src/common-properties/controls/checkboxset/checkboxset.scss +6 -0
  61. package/src/common-properties/controls/radioset/radioset.jsx +25 -1
  62. package/src/common-properties/controls/radioset/radioset.scss +19 -0
  63. package/src/common-properties/form/ControlInfo.js +3 -0
  64. package/src/common-properties/form/EditorForm.js +24 -0
  65. package/src/common-properties/properties-controller.js +23 -10
  66. package/src/common-properties/util/L10nProvider.js +6 -0
  67. package/src/object-model/config-utils.js +1 -0
  68. package/src/object-model/layout-dimensions.js +10 -0
  69. package/src/object-model/object-model.js +12 -0
  70. package/src/object-model/redux/canvas-store.js +4 -1
  71. package/src/object-model/redux/reducers/bottompanel.js +1 -3
  72. package/src/object-model/redux/reducers/texttoolbar.js +29 -0
  73. package/src/toolbar/toolbar-action-item.jsx +9 -6
  74. package/src/toolbar/toolbar-overflow-item.jsx +1 -0
  75. package/src/toolbar/toolbar.jsx +12 -15
  76. package/src/tooltip/tooltip.jsx +13 -4
  77. package/stats.html +1 -1
  78. package/dist/canvas-controller-40beba7d.js +0 -2
  79. package/dist/canvas-controller-40beba7d.js.map +0 -1
  80. package/dist/canvas-controller-f62a8ef7.js +0 -2
  81. package/dist/canvas-controller-f62a8ef7.js.map +0 -1
  82. package/dist/common-canvas-f0f1afd7.js +0 -2
  83. package/dist/common-canvas-f0f1afd7.js.map +0 -1
  84. package/dist/common-canvas-feb8cd7a.js +0 -2
  85. package/dist/common-canvas-feb8cd7a.js.map +0 -1
  86. package/dist/common-properties-1d4c875b.js +0 -2
  87. package/dist/common-properties-1d4c875b.js.map +0 -1
  88. package/dist/common-properties-da3999f5.js +0 -2
  89. package/dist/common-properties-da3999f5.js.map +0 -1
  90. package/dist/toolbar-2baadd0f.js +0 -2
  91. package/dist/toolbar-2baadd0f.js.map +0 -1
  92. package/dist/toolbar-d07d4d8a.js +0 -2
  93. package/dist/toolbar-d07d4d8a.js.map +0 -1
@@ -26,6 +26,12 @@ import * as d3Fetch from "d3-fetch";
26
26
  import * as d3Zoom from "./d3-zoom-extension/src";
27
27
  const d3 = Object.assign({}, d3Drag, d3Ease, d3Selection, d3Fetch, d3Zoom);
28
28
 
29
+ const markdownIt = require("markdown-it")({
30
+ html: false, // Don't allow HTML to be executed in comments.
31
+ linkify: false, // Don't convert strings, in URL format, to be links.
32
+ typographer: true
33
+ });
34
+
29
35
  import { cloneDeep, escape as escapeText, forOwn, get,
30
36
  unescape as unescapeText } from "lodash";
31
37
  import { ASSOC_RIGHT_SIDE_CURVE, ASSOCIATION_LINK, NODE_LINK, COMMENT_LINK,
@@ -50,8 +56,10 @@ import SvgCanvasNodes from "./svg-canvas-utils-nodes.js";
50
56
  import SvgCanvasComments from "./svg-canvas-utils-comments.js";
51
57
  import SvgCanvasLinks from "./svg-canvas-utils-links.js";
52
58
  import SvgCanvasDecs from "./svg-canvas-utils-decs.js";
59
+ import SvgCanvasMarkdown from "./svg-canvas-utils-markdown.js";
53
60
  import SVGCanvasPipeline from "./svg-canvas-pipeline";
54
61
 
62
+
55
63
  const showLinksTime = false;
56
64
 
57
65
  const BACKSPACE_KEY = 8;
@@ -63,6 +71,15 @@ const RIGHT_ARROW_KEY = 39;
63
71
  const DOWN_ARROW_KEY = 40;
64
72
  const DELETE_KEY = 46;
65
73
  const A_KEY = 65;
74
+ const B_KEY = 66;
75
+ const E_KEY = 69;
76
+ const I_KEY = 73;
77
+ const K_KEY = 75;
78
+ const X_KEY = 88;
79
+ const LAB_KEY = 188; // Left angle bracket <
80
+ const RAB_KEY = 190; // Right angle bracket >
81
+ const SEVEN_KEY = 55;
82
+ const EIGHT_KEY = 56;
66
83
 
67
84
  const SCROLL_PADDING = 12;
68
85
 
@@ -164,13 +181,12 @@ export default class SVGCanvasRenderer {
164
181
  // option is switched on.
165
182
  this.dragNewLinkOverNode = null;
166
183
 
167
-
168
184
  // Flag to indicate if the current drag operation is for a node that can
169
185
  // be inserted into a link. Such a node would need input and output ports.
170
186
  this.existingNodeInsertableIntoLink = false;
171
187
 
172
188
  // Flag to indicate if the current drag operation is for a node that can
173
- // be attachd to a a detachd link.
189
+ // be attached to a detached link.
174
190
  this.existingNodeAttachableToDetachedLinks = false;
175
191
 
176
192
  // Allow us to track when a selection is being made so there is
@@ -731,9 +747,9 @@ export default class SVGCanvasRenderer {
731
747
  return this.transformPos({ x: x - Math.round(svgRect.left), y: y - Math.round(svgRect.top) });
732
748
  }
733
749
 
734
- // Transforms the x and y fields of the object passed in by the current zoom
750
+ // Transforms the x and y fields passed in by the current zoom
735
751
  // transformation amounts to convert a coordinate position in screen pixels
736
- // to a coordinate position in zoomed pixels.
752
+ // to a canvas coordinate position.
737
753
  transformPos(pos) {
738
754
  return {
739
755
  x: (pos.x - this.zoomTransform.x) / this.zoomTransform.k,
@@ -741,6 +757,16 @@ export default class SVGCanvasRenderer {
741
757
  };
742
758
  }
743
759
 
760
+ // Transforms the x and y fields passed in by the current zoom
761
+ // transformation amounts to convert a canvas coordinate position
762
+ // to a coordinate position in screen pixels.
763
+ unTransformPos(pos) {
764
+ return {
765
+ x: (pos.x * this.zoomTransform.k) + this.zoomTransform.x,
766
+ y: (pos.y * this.zoomTransform.k) + this.zoomTransform.y
767
+ };
768
+ }
769
+
744
770
  // Transforms the x, y, height and width fields of the object passed in by the
745
771
  // current zoom transformation amounts to convert coordinate positions and
746
772
  // dimensions in screen pixels to coordinate positions and dimensions in
@@ -1840,6 +1866,7 @@ export default class SVGCanvasRenderer {
1840
1866
  }
1841
1867
  } else {
1842
1868
  this.zoomCanvasBackground(d3Event);
1869
+ this.zoomCommentToolbar();
1843
1870
  }
1844
1871
  }
1845
1872
 
@@ -1940,6 +1967,29 @@ export default class SVGCanvasRenderer {
1940
1967
  }
1941
1968
  }
1942
1969
 
1970
+ // Repositions the comment toolbar so it is always over the top of the
1971
+ // comment being edited.
1972
+ zoomCommentToolbar() {
1973
+ if (this.config.enableMarkdownInComments && this.dispUtils.isDisplayingFullPage()) {
1974
+ // If a node label or text decoration is being edited com will be undefined.
1975
+ const com = this.activePipeline.getComment(this.editingTextId);
1976
+ if (com) {
1977
+ const pos = this.getCommentToolbarPos(com);
1978
+ this.canvasController.moveTextToolbar(pos.x, pos.y);
1979
+ }
1980
+ }
1981
+ }
1982
+
1983
+ // Returns a position object that describes the position in page coordinates
1984
+ // of the comment toolbar so that it is positioned above the comment being edited.
1985
+ getCommentToolbarPos(com) {
1986
+ const pos = this.unTransformPos({ x: com.x_pos, y: com.y_pos });
1987
+ return {
1988
+ x: pos.x + this.canvasLayout.commentToolbarPosX,
1989
+ y: pos.y + this.canvasLayout.commentToolbarPosY
1990
+ };
1991
+ }
1992
+
1943
1993
  // Returns a new zoom which is the result of incrementing the current zoom
1944
1994
  // by the amount since the previous d3Event transform amount.
1945
1995
  // We calculate increments because d3Event.transform is not based on
@@ -5112,7 +5162,10 @@ export default class SVGCanvasRenderer {
5112
5162
  .attr("height", (c) => c.height)
5113
5163
  .select("div")
5114
5164
  .attr("style", (c) => this.getNodeLabelStyle(c, "default"))
5115
- .html((c) => escapeText(c.content));
5165
+ .html((c) => (
5166
+ this.config.enableMarkdownInComments
5167
+ ? markdownIt.render(c.content)
5168
+ : escapeText(c.content)));
5116
5169
  }
5117
5170
 
5118
5171
  // Attaches the appropriate listeners to the comment groups.
@@ -5120,7 +5173,7 @@ export default class SVGCanvasRenderer {
5120
5173
  commentGrps
5121
5174
  .on("mouseenter", (d3Event, d) => {
5122
5175
  this.setCommentStyles(d, "hover", d3.select(d3Event.currentTarget));
5123
- if (this.config.enableEditingActions) {
5176
+ if (this.config.enableEditingActions && d.id !== this.editingTextId) {
5124
5177
  this.createCommentPort(d3Event.currentTarget, d);
5125
5178
  }
5126
5179
  })
@@ -5147,6 +5200,7 @@ export default class SVGCanvasRenderer {
5147
5200
  if (this.config.enableEditingActions) {
5148
5201
  CanvasUtils.stopPropagationAndPreventDefault(d3Event);
5149
5202
 
5203
+ this.deleteCommentPort(d3Event.currentTarget);
5150
5204
  this.displayCommentTextArea(d, d3Event.currentTarget);
5151
5205
 
5152
5206
  this.canvasController.clickActionHandler({
@@ -5204,8 +5258,8 @@ export default class SVGCanvasRenderer {
5204
5258
 
5205
5259
  commentGrp
5206
5260
  .append("circle")
5207
- .attr("cx", 0 - this.canvasLayout.commentHighlightGap)
5208
- .attr("cy", 0 - this.canvasLayout.commentHighlightGap)
5261
+ .attr("cx", (com) => com.width / 2)
5262
+ .attr("cy", (com) => com.height + this.canvasLayout.commentHighlightGap)
5209
5263
  .attr("r", this.canvasLayout.commentPortRadius)
5210
5264
  .attr("class", "d3-comment-port-circle")
5211
5265
  .on("mousedown", (d3Event, cd) => {
@@ -5265,7 +5319,7 @@ export default class SVGCanvasRenderer {
5265
5319
  }
5266
5320
 
5267
5321
  displayCommentTextArea(d, parentDomObj) {
5268
- this.displayTextArea({
5322
+ this.editingTextData = {
5269
5323
  id: d.id,
5270
5324
  text: d.content,
5271
5325
  singleLine: false,
@@ -5278,10 +5332,114 @@ export default class SVGCanvasRenderer {
5278
5332
  height: d.height,
5279
5333
  className: "d3-comment-entry",
5280
5334
  parentDomObj: parentDomObj,
5335
+ keyboardInputCallback: this.config.enableMarkdownInComments ? this.commentKeyboardHandler.bind(this) : null,
5281
5336
  autoSizeCallback: this.autoSizeComment.bind(this),
5282
5337
  saveTextChangesCallback: this.saveCommentChanges.bind(this),
5283
- closeTextAreaCallback: null
5284
- });
5338
+ closeTextAreaCallback: this.closeCommentTextArea.bind(this)
5339
+ };
5340
+ this.displayTextArea(this.editingTextData);
5341
+ if (this.config.enableMarkdownInComments && this.dispUtils.isDisplayingFullPage()) {
5342
+ const pos = this.getCommentToolbarPos(d);
5343
+ this.canvasController.openTextToolbar(pos.x, pos.y,
5344
+ this.markdownActionHandler.bind(this),
5345
+ this.blurInTextToolbar.bind(this));
5346
+ }
5347
+ }
5348
+
5349
+ // Handles markdown actions initiated through the keyboard.
5350
+ commentKeyboardHandler(d3Event) {
5351
+ const action = this.getMarkdownAction(d3Event);
5352
+ if (action) {
5353
+ if (action !== "return") {
5354
+ CanvasUtils.stopPropagationAndPreventDefault(d3Event);
5355
+ }
5356
+ this.markdownActionHandler(action, d3Event);
5357
+ }
5358
+ }
5359
+
5360
+ // Called when the blur event occurs for the text toolbar.
5361
+ blurInTextToolbar(evt) {
5362
+ // When Cypress tests are running a call to focus() in addTextToTextArea()
5363
+ // can cause an incorrect blur event to be generated for the text toolbar
5364
+ // (where relatedTarget is null). This flag therefore allows us to avoid
5365
+ // thus blue events that occur while addTextToTextArea() is executing.
5366
+ if (this.addingTextToTextArea) {
5367
+ return;
5368
+ }
5369
+
5370
+ // If there is a relatedTarget and it is set to one of the elements for the
5371
+ // textarea, texttoolbar, etc we ignore the blur event.
5372
+ if (evt.relatedTarget &&
5373
+ (this.getParentElementWithClass(evt.relatedTarget, "d3-comment-entry") ||
5374
+ this.getParentElementWithClass(evt.relatedTarget, "text-toolbar") ||
5375
+ this.getParentElementWithClass(evt.relatedTarget, "bx--overflow-menu-options__btn"))) {
5376
+ return;
5377
+ }
5378
+
5379
+ // If the blur event is ocurring for an object outside of the textarea and
5380
+ // text toolbar we save the current text and close the textarea.
5381
+ const commentParent = d3.select(this.editingTextData.parentDomObj);
5382
+ const foreignObject = commentParent.selectAll(".d3-text-entry-fo");
5383
+ const commentEntry = this.canvasDiv.selectAll(".d3-comment-entry");
5384
+ const commentEntryElement = commentEntry.node();
5385
+ this.saveAndCloseTextArea(foreignObject, this.editingTextData, commentEntryElement.value, evt);
5386
+ }
5387
+
5388
+ // Applies a markdown action to the comment text being edited using
5389
+ // the same commands as the toolbar.
5390
+ getMarkdownAction(d3Event) {
5391
+ if (CanvasUtils.isCmndCtrlPressed(d3Event)) {
5392
+ switch (d3Event.keyCode) {
5393
+ case B_KEY: return "bold";
5394
+ case I_KEY: return "italics";
5395
+ case X_KEY: return d3Event.shiftKey ? "strikethrough" : null;
5396
+ case SEVEN_KEY: return d3Event.shiftKey ? "numberedList" : null;
5397
+ case EIGHT_KEY: return d3Event.shiftKey ? "bulletedList" : null;
5398
+ case E_KEY: return "code";
5399
+ case K_KEY: return "link";
5400
+ case LAB_KEY: return "decreaseHashes";
5401
+ case RAB_KEY: return d3Event.shiftKey ? "quote" : "increaseHashes";
5402
+ default:
5403
+ }
5404
+ } else if (d3Event.keyCode === RETURN_KEY) {
5405
+ return "return";
5406
+ }
5407
+
5408
+ return null;
5409
+ }
5410
+
5411
+ // Handles any actions requested on the comment text to add markdown
5412
+ // characters to the text. evt can be either a d3Event object from D3 when
5413
+ // this method is called from keyboard entry in the textarea or it can be
5414
+ // a synthetic event object from React when called from the text toolbar.
5415
+ markdownActionHandler(action, evt) {
5416
+ this.logger.log("markdownActionHandler - action = " + action);
5417
+
5418
+ const commentEntry = this.canvasDiv.selectAll(".d3-comment-entry");
5419
+ const commentEntryElement = commentEntry.node();
5420
+ const start = commentEntryElement.selectionStart;
5421
+ const end = commentEntryElement.selectionEnd;
5422
+ const text = commentEntryElement.value;
5423
+
5424
+ const mdObj = SvgCanvasMarkdown.processMarkdownAction(action, text, start, end);
5425
+ if (mdObj) {
5426
+ CanvasUtils.stopPropagationAndPreventDefault(evt);
5427
+ this.addTextToTextArea(mdObj, commentEntryElement);
5428
+ }
5429
+ }
5430
+
5431
+ // Replaces the text in the currently displayed textarea with the text
5432
+ // passed in. We use execCommand because this adds the inserted text to the
5433
+ // textarea's undo/redo stack whereas setting the text directly into the
5434
+ // textarea control does not.
5435
+ addTextToTextArea(mdObj, commentEntryElement) {
5436
+ this.addingTextToTextArea = true;
5437
+ const text = unescapeText(mdObj.newText);
5438
+ commentEntryElement.focus();
5439
+ commentEntryElement.select();
5440
+ document.execCommand("insertText", false, text);
5441
+ commentEntryElement.setSelectionRange(mdObj.newStart, mdObj.newEnd);
5442
+ this.addingTextToTextArea = false;
5285
5443
  }
5286
5444
 
5287
5445
  autoSizeComment(textArea, foreignObject, data) {
@@ -5313,6 +5471,10 @@ export default class SVGCanvasRenderer {
5313
5471
  this.canvasController.editActionHandler(data);
5314
5472
  }
5315
5473
 
5474
+ closeCommentTextArea() {
5475
+ this.canvasController.closeTextToolbar();
5476
+ }
5477
+
5316
5478
  displayNodeLabelTextArea(node, parentDomObj) {
5317
5479
  d3.select(parentDomObj).selectAll("div")
5318
5480
  .attr("style", "display:none;");
@@ -5426,7 +5588,7 @@ export default class SVGCanvasRenderer {
5426
5588
 
5427
5589
  const foreignObject = d3.select(data.parentDomObj)
5428
5590
  .append("foreignObject")
5429
- .attr("class", "d3-foreign-object")
5591
+ .attr("class", "d3-foreign-object d3-text-entry-fo")
5430
5592
  .attr("width", data.width)
5431
5593
  .attr("height", data.height)
5432
5594
  .attr("x", data.xPos)
@@ -5453,6 +5615,11 @@ export default class SVGCanvasRenderer {
5453
5615
  !that.textAreaAllowedKeys(d3Event)) {
5454
5616
  CanvasUtils.stopPropagationAndPreventDefault(d3Event);
5455
5617
  }
5618
+ // Call any specific keyboard handler for the type of
5619
+ // text being edited.
5620
+ if (data.keyboardInputCallback) {
5621
+ data.keyboardInputCallback(d3Event);
5622
+ }
5456
5623
  })
5457
5624
  .on("keyup", function(d3Event) {
5458
5625
  data.autoSizeCallback(this, foreignObject, data);
@@ -5472,20 +5639,14 @@ export default class SVGCanvasRenderer {
5472
5639
  that.textAreaEscKeyPressed = false;
5473
5640
  return;
5474
5641
  }
5475
- // If there is no text for the label and textCanBeEmpty is false
5476
- // just return so label returns to what it was before editing started.
5477
- if (!this.value && !data.textCanBeEmpty) {
5478
- CanvasUtils.stopPropagationAndPreventDefault(d3Event);
5479
- that.closeTextArea(foreignObject, data);
5642
+
5643
+ // If the user clicked on an element in the text toolbar to cause the
5644
+ // blur event, just return.
5645
+ if (d3Event.relatedTarget && that.getParentElementWithClass(d3Event.relatedTarget, "text-toolbar")) {
5480
5646
  return;
5481
5647
  }
5482
- const newText = this.value; // Save the text before closing the foreign object
5483
- that.closeTextArea(foreignObject, data);
5484
- if (data.text !== newText) {
5485
- that.isCommentBeingUpdated = true;
5486
- data.saveTextChangesCallback(data.id, newText, that.textAreaHeight, data);
5487
- that.isCommentBeingUpdatd = false;
5488
- }
5648
+
5649
+ that.saveAndCloseTextArea(foreignObject, data, this.value, d3Event);
5489
5650
  })
5490
5651
  .on("focus", function(d3Event, d) {
5491
5652
  that.logger.log("Text area - focus");
@@ -5501,6 +5662,23 @@ export default class SVGCanvasRenderer {
5501
5662
  textArea.node().setSelectionRange(data.text.length, data.text.length);
5502
5663
  }
5503
5664
 
5665
+ saveAndCloseTextArea(foreignObject, data, newValue, d3Event) {
5666
+ // If there is no text for the label and textCanBeEmpty is false
5667
+ // just return, so label returns to what it was before editing started.
5668
+ if (!newValue && !data.textCanBeEmpty) {
5669
+ CanvasUtils.stopPropagationAndPreventDefault(d3Event);
5670
+ this.closeTextArea(foreignObject, data);
5671
+ return;
5672
+ }
5673
+ const newText = newValue; // Save the text before closing the foreign object
5674
+ this.closeTextArea(foreignObject, data);
5675
+ if (data.text !== newText) {
5676
+ this.isCommentBeingUpdated = true;
5677
+ data.saveTextChangesCallback(data.id, newText, this.textAreaHeight, data);
5678
+ this.isCommentBeingUpdatd = false;
5679
+ }
5680
+ }
5681
+
5504
5682
  // Closes the text area and resets the flags.
5505
5683
  closeTextArea(foreignObject, data) {
5506
5684
  if (data.closeTextAreaCallback) {
@@ -6744,9 +6922,9 @@ export default class SVGCanvasRenderer {
6744
6922
  });
6745
6923
  });
6746
6924
 
6747
- // For NORTH and SOUTH links we sort linksDirArray by the x co-ordinate
6925
+ // For NORTH and SOUTH links we sort linksDirArray by the x coordinate
6748
6926
  // of the end of each link. For EAST and WEST we sort by the y
6749
- // co-ordinate.
6927
+ // coordinate.
6750
6928
  if (dir === NORTH || dir === SOUTH) {
6751
6929
  linksDirArray = linksDirArray.sort((a, b) => (a.x > b.x ? 1 : -1));
6752
6930
  } else {