@joint/core 4.0.2 → 4.0.4

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.
@@ -1,4 +1,4 @@
1
- /*! JointJS v4.0.2 (2024-04-09) - JavaScript diagramming library
1
+ /*! JointJS v4.0.4 (2024-05-31) - JavaScript diagramming library
2
2
 
3
3
 
4
4
  This Source Code Form is subject to the terms of the Mozilla Public
@@ -1,4 +1,4 @@
1
- /*! JointJS v4.0.2 (2024-04-09) - JavaScript diagramming library
1
+ /*! JointJS v4.0.4 (2024-05-31) - JavaScript diagramming library
2
2
 
3
3
 
4
4
  This Source Code Form is subject to the terms of the Mozilla Public
package/dist/version.mjs CHANGED
@@ -1,3 +1,3 @@
1
- var version = "4.0.2";
1
+ var version = "4.0.4";
2
2
 
3
3
  export { version };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@joint/core",
3
3
  "title": "JointJS",
4
- "version": "4.0.2",
4
+ "version": "4.0.4",
5
5
  "description": "JavaScript diagramming library",
6
6
  "sideEffects": false,
7
7
  "main": "./dist/joint.min.js",
@@ -37,6 +37,7 @@
37
37
  "access": "public"
38
38
  },
39
39
  "scripts": {
40
+ "prepublishOnly": "echo \"Publishing via NPM is not allowed!\" && exit 1",
40
41
  "prepack": "yarn run dist",
41
42
  "build": "grunt install",
42
43
  "test": "grunt test",
@@ -188,4 +189,4 @@
188
189
  "finder",
189
190
  "shortest-path-finder"
190
191
  ]
191
- }
192
+ }
@@ -433,15 +433,20 @@ export const CellView = View.extend({
433
433
 
434
434
  getLinkEnd: function(magnet, ...args) {
435
435
 
436
- var model = this.model;
437
- var id = model.id;
438
- var port = this.findAttribute('port', magnet);
436
+ const model = this.model;
437
+ const id = model.id;
438
+ // Find a node with the `port` attribute set on it.
439
+ const portNode = this.findAttributeNode('port', magnet);
439
440
  // Find a unique `selector` of the element under pointer that is a magnet.
440
- var selector = magnet.getAttribute('joint-selector');
441
+ const selector = magnet.getAttribute('joint-selector');
441
442
 
442
- var end = { id: id };
443
+ const end = { id: id };
443
444
  if (selector != null) end.magnet = selector;
444
- if (port != null) {
445
+ if (portNode != null) {
446
+ let port = portNode.getAttribute('port');
447
+ if (portNode.getAttribute('port-id-type') === 'number') {
448
+ port = parseInt(port, 10);
449
+ }
445
450
  end.port = port;
446
451
  if (!model.hasPort(port) && !selector) {
447
452
  // port created via the `port` attribute (not API)
@@ -5,7 +5,7 @@ import { addClassNamePrefix, merge, assign, isObject, isFunction, clone, isPerce
5
5
  import { Point, Line, Path, normalizeAngle, Rect, Polyline } from '../g/index.mjs';
6
6
  import * as routers from '../routers/index.mjs';
7
7
  import * as connectors from '../connectors/index.mjs';
8
-
8
+ import { env } from '../env/index.mjs';
9
9
 
10
10
  const Flags = {
11
11
  TOOLS: CellView.Flags.TOOLS,
@@ -99,6 +99,11 @@ export const LinkView = CellView.extend({
99
99
  this.updateHighlighters(true);
100
100
  this.updateTools(opt);
101
101
  flags = this.removeFlag(flags, [Flags.RENDER, Flags.UPDATE, Flags.LABELS, Flags.TOOLS, Flags.CONNECTOR]);
102
+
103
+ if (env.test('isSafari')) {
104
+ this.__fixSafariBug268376();
105
+ }
106
+
102
107
  return flags;
103
108
  }
104
109
 
@@ -151,6 +156,19 @@ export const LinkView = CellView.extend({
151
156
  return flags;
152
157
  },
153
158
 
159
+ __fixSafariBug268376: function() {
160
+ // Safari has a bug where any change after the first render is not reflected in the DOM.
161
+ // https://bugs.webkit.org/show_bug.cgi?id=268376
162
+ const { el } = this;
163
+ const childNodes = Array.from(el.childNodes);
164
+ const fragment = document.createDocumentFragment();
165
+ for (let i = 0, n = childNodes.length; i < n; i++) {
166
+ el.removeChild(childNodes[i]);
167
+ fragment.appendChild(childNodes[i]);
168
+ }
169
+ el.appendChild(fragment);
170
+ },
171
+
154
172
  requestConnectionUpdate: function(opt) {
155
173
  this.requestUpdate(this.getFlag(Flags.UPDATE), opt);
156
174
  },
@@ -7,6 +7,8 @@ function isTextInUse(_value, _node, attrs) {
7
7
  return (attrs.text !== undefined);
8
8
  }
9
9
 
10
+ const FONT_ATTRIBUTES = ['font-weight', 'font-family', 'font-size', 'letter-spacing', 'text-transform'];
11
+
10
12
  const textAttributesNS = {
11
13
 
12
14
  'line-height': {
@@ -122,18 +124,28 @@ const textAttributesNS = {
122
124
  var text = value.text;
123
125
  if (text === undefined) text = attrs.text;
124
126
  if (text !== undefined) {
127
+
125
128
  const breakTextFn = value.breakText || breakText;
126
129
  const computedStyles = getComputedStyle(node);
130
+ const wrapFontAttributes = {};
131
+ // The font size attributes must be set on the node
132
+ // to get the correct text wrapping.
133
+ // TODO: set the native SVG attributes before special attributes
134
+ for (let i = 0; i < FONT_ATTRIBUTES.length; i++) {
135
+ const name = FONT_ATTRIBUTES[i];
136
+ if (name in attrs) {
137
+ node.setAttribute(name, attrs[name]);
138
+ }
139
+ // Note: computedStyles is a live object
140
+ // i.e. the properties are evaluated when accessed.
141
+ wrapFontAttributes[name] = computedStyles[name];
142
+ }
127
143
 
128
- wrappedText = breakTextFn('' + text, size, {
129
- 'font-weight': computedStyles.fontWeight,
130
- 'font-family': computedStyles.fontFamily,
131
- 'text-transform': computedStyles.textTransform,
132
- 'font-size': computedStyles.fontSize,
133
- 'letter-spacing': computedStyles.letterSpacing,
134
- // The `line-height` attribute in SVG is JoinJS specific.
135
- 'lineHeight': attrs['line-height'],
136
- }, {
144
+ // The `line-height` attribute in SVG is JoinJS specific.
145
+ // TODO: change the `lineHeight` to breakText option.
146
+ wrapFontAttributes.lineHeight = attrs['line-height'];
147
+
148
+ wrappedText = breakTextFn('' + text, size, wrapFontAttributes, {
137
149
  // Provide an existing SVG Document here
138
150
  // instead of creating a temporary one over again.
139
151
  svgDocument: this.paper.svg,
@@ -147,7 +159,11 @@ const textAttributesNS = {
147
159
  wrappedText = '';
148
160
  }
149
161
  textAttributesNS.text.set.call(this, wrappedText, refBBox, node, attrs);
150
- }
162
+ },
163
+ // We expose the font attributes list to allow
164
+ // the user to take other custom font attributes into account
165
+ // when wrapping the text.
166
+ FONT_ATTRIBUTES
151
167
  },
152
168
 
153
169
  'title': {
@@ -67,7 +67,7 @@ export const GridLayer = PaperLayer.extend({
67
67
 
68
68
  gridSettings.forEach((gridLayerSetting, index) => {
69
69
 
70
- const id = 'pattern_' + index;
70
+ const id = this._getPatternId(index);
71
71
  const options = merge({}, gridLayerSetting);
72
72
  const { scaleFactor = 1 } = options;
73
73
  options.width = gridSize * scaleFactor || 1;
@@ -107,12 +107,16 @@ export const GridLayer = PaperLayer.extend({
107
107
  }
108
108
  gridSettings.forEach((options, index) => {
109
109
  if (isFunction(options.update)) {
110
- const vPattern = patterns['pattern_' + index];
110
+ const vPattern = patterns[this._getPatternId(index)];
111
111
  options.update(vPattern.node.firstChild, options, paper);
112
112
  }
113
113
  });
114
114
  },
115
115
 
116
+ _getPatternId(index) {
117
+ return `pattern_${this.options.paper.cid}_${index}`;
118
+ },
119
+
116
120
  _getGridRefs() {
117
121
  let { _gridCache: grid } = this;
118
122
  if (grid) return grid;
package/src/dia/ports.mjs CHANGED
@@ -731,6 +731,13 @@ export const elementViewPortPrototype = {
731
731
  'port-group': port.group
732
732
  });
733
733
 
734
+ // If the port ID is a number, we need to add
735
+ // extra information to the port element to distinguish
736
+ // between ports with the same ID but different types.
737
+ if (util.isNumber(port.id)) {
738
+ portElement.attr('port-id-type', 'number');
739
+ }
740
+
734
741
  const labelMarkupDef = this._getPortLabelMarkup(port.label);
735
742
  if (Array.isArray(labelMarkupDef)) {
736
743
  // JSON Markup
package/src/env/index.mjs CHANGED
@@ -7,6 +7,11 @@ export const env = {
7
7
  svgforeignobject: function() {
8
8
  return !!document.createElementNS &&
9
9
  /SVGForeignObject/.test(({}).toString.call(document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject')));
10
+ },
11
+
12
+ // works for iOS browsers too
13
+ isSafari: function() {
14
+ return /Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor);
10
15
  }
11
16
  },
12
17
 
@@ -48,12 +48,14 @@ const Arrowhead = ToolView.extend({
48
48
  evt.stopPropagation();
49
49
  evt.preventDefault();
50
50
  var relatedView = this.relatedView;
51
+ var paper = relatedView.paper;
51
52
  relatedView.model.startBatch('arrowhead-move', { ui: true, tool: this.cid });
52
53
  relatedView.startArrowheadMove(this.arrowheadType);
53
54
  this.delegateDocumentEvents();
54
- relatedView.paper.undelegateEvents();
55
+ paper.undelegateEvents();
55
56
  this.focus();
56
57
  this.el.style.pointerEvents = 'none';
58
+ relatedView.notifyPointerdown(...paper.getPointerArgs(evt));
57
59
  },
58
60
  onPointerMove: function(evt) {
59
61
  var normalizedEvent = util.normalizeEvent(evt);
package/src/mvc/View.mjs CHANGED
@@ -63,23 +63,25 @@ export const View = ViewBase.extend({
63
63
  return this;
64
64
  },
65
65
 
66
- findAttribute: function(attributeName, node) {
67
-
68
- var currentNode = node;
69
-
66
+ findAttributeNode: function(attributeName, node) {
67
+ let currentNode = node;
70
68
  while (currentNode && currentNode.nodeType === 1) {
71
- var attributeValue = currentNode.getAttribute(attributeName);
72
69
  // attribute found
73
- if (attributeValue) return attributeValue;
70
+ // (empty value does not count as attribute found)
71
+ if (currentNode.getAttribute(attributeName)) return currentNode;
74
72
  // do not climb up the DOM
75
73
  if (currentNode === this.el) return null;
76
74
  // try parent node
77
75
  currentNode = currentNode.parentNode;
78
76
  }
79
-
80
77
  return null;
81
78
  },
82
79
 
80
+ findAttribute: function(attributeName, node) {
81
+ const matchedNode = this.findAttributeNode(attributeName, node);
82
+ return matchedNode && matchedNode.getAttribute(attributeName);
83
+ },
84
+
83
85
  // Override the mvc ViewBase `_ensureElement()` method in order to create an
84
86
  // svg element (e.g., `<g>`) node that wraps all the nodes of the Cell view.
85
87
  // Expose class name setter as a separate method.
package/types/joint.d.ts CHANGED
@@ -12,6 +12,16 @@ export namespace config {
12
12
 
13
13
  type NativeEvent = Event;
14
14
 
15
+ type _DeepRequired<T> = {
16
+ [P in keyof T]-?: T[P] extends object ? _DeepRequired<T[P]> : T[P];
17
+ };
18
+
19
+ type _DeepPartial<T> = {
20
+ [P in keyof T]?: T[P] extends object ? _DeepPartial<T[P]> : T[P];
21
+ };
22
+
23
+ type DeepPartial<T> = _DeepPartial<_DeepRequired<T>>;
24
+
15
25
  export namespace dia {
16
26
 
17
27
  type Event = mvc.TriggeredEvent;
@@ -327,7 +337,7 @@ export namespace dia {
327
337
 
328
338
  class Cell<A extends ObjectHash = Cell.Attributes, S extends mvc.ModelSetOptions = dia.ModelSetOptions> extends mvc.Model<A, S> {
329
339
 
330
- constructor(attributes?: A, opt?: Cell.ConstructorOptions);
340
+ constructor(attributes?: DeepPartial<A>, opt?: Cell.ConstructorOptions);
331
341
 
332
342
  id: Cell.ID;
333
343
  graph: Graph;
@@ -361,7 +371,7 @@ export namespace dia {
361
371
  isEmbedded(): boolean;
362
372
 
363
373
  prop(key: Path): any;
364
- prop(object: Partial<A>, opt?: Cell.Options): this;
374
+ prop(object: DeepPartial<A>, opt?: Cell.Options): this;
365
375
  prop(key: Path, value: any, opt?: Cell.Options): this;
366
376
 
367
377
  removeProp(path: Path, opt?: Cell.Options): this;
@@ -3302,6 +3312,8 @@ export namespace mvc {
3302
3312
 
3303
3313
  isMounted(): boolean;
3304
3314
 
3315
+ protected findAttributeNode(attributeName: string, node: Element): Element | null;
3316
+
3305
3317
  protected init(): void;
3306
3318
 
3307
3319
  protected onRender(): void;