microboard-temp 0.2.5 → 0.3.1

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.
@@ -33402,6 +33402,7 @@ class BaseItem extends Mbr {
33402
33402
  transformationRenderBlock = undefined;
33403
33403
  board;
33404
33404
  id;
33405
+ onRemoveCallbacks = [];
33405
33406
  shouldUseCustomRender = false;
33406
33407
  shouldRenderOutsideViewRect = true;
33407
33408
  itemType = "";
@@ -33479,6 +33480,12 @@ class BaseItem extends Mbr {
33479
33480
  break;
33480
33481
  }
33481
33482
  }
33483
+ addOnRemoveCallback(cb) {
33484
+ this.onRemoveCallbacks.push(cb);
33485
+ }
33486
+ onRemove() {
33487
+ this.onRemoveCallbacks.forEach((cb) => cb());
33488
+ }
33482
33489
  render(context) {}
33483
33490
  renderHTML(documentFactory) {
33484
33491
  return documentFactory.createElement("div");
@@ -38735,6 +38742,9 @@ class VideoItem extends BaseItem {
38735
38742
  this.loadCallbacks.push(callback);
38736
38743
  };
38737
38744
  getStorageId() {
38745
+ if (!this.isStorageUrl) {
38746
+ return;
38747
+ }
38738
38748
  return this.url.split("/").pop();
38739
38749
  }
38740
38750
  getIsStorageUrl() {
@@ -39007,6 +39017,13 @@ class VideoItem extends BaseItem {
39007
39017
  linkElem.click();
39008
39018
  }
39009
39019
  }
39020
+ onRemove() {
39021
+ const storageId = this.getStorageId();
39022
+ if (storageId) {
39023
+ deleteMedia([storageId], this.board.getBoardId());
39024
+ }
39025
+ super.onRemove();
39026
+ }
39010
39027
  }
39011
39028
  // src/Items/Image/calculatePosition.ts
39012
39029
  function calculatePosition(boardImage, board) {
@@ -39437,432 +39454,122 @@ var captureFrame = (frameTime, video) => {
39437
39454
  return null;
39438
39455
  }
39439
39456
  };
39440
- // src/Items/Audio/Audio.ts
39441
- class AudioItem extends BaseItem {
39457
+ // src/Items/Placeholder/Placeholder.ts
39458
+ var PlaceholderImg = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
39459
+ <path d="M5 11.1L7 9.1L12.5 14.6L16 11.1L19 14.1V5H5V11.1ZM4 3H20C20.2652 3 20.5196 3.10536 20.7071 3.29289C20.8946 3.48043 21 3.73478 21 4V20C21 20.2652 20.8946 20.5196 20.7071 20.7071C20.5196 20.8946 20.2652 21 20 21H4C3.73478 21 3.48043 20.8946 3.29289 20.7071C3.10536 20.5196 3 20.2652 3 20V4C3 3.73478 3.10536 3.48043 3.29289 3.29289C3.48043 3.10536 3.73478 3 4 3ZM15.5 10C15.1022 10 14.7206 9.84196 14.4393 9.56066C14.158 9.27936 14 8.89782 14 8.5C14 8.10218 14.158 7.72064 14.4393 7.43934C14.7206 7.15804 15.1022 7 15.5 7C15.8978 7 16.2794 7.15804 16.5607 7.43934C16.842 7.72064 17 8.10218 17 8.5C17 8.89782 16.842 9.27936 16.5607 9.56066C16.2794 9.84196 15.8978 10 15.5 10Z" fill="white" fill-opacity="0.6"/>
39460
+ </svg>`;
39461
+
39462
+ class Placeholder extends BaseItem {
39442
39463
  events;
39443
- extension;
39444
- itemType = "Audio";
39464
+ miroData;
39465
+ backgroundColor;
39466
+ icon;
39467
+ itemType = "Placeholder";
39468
+ shapeType = "Rectangle";
39445
39469
  parent = "Board";
39446
39470
  transformation;
39447
- linkTo;
39471
+ path = Shapes[this.shapeType].path.copy();
39472
+ mbr = Shapes[this.shapeType].path.getMbr().copy();
39448
39473
  subject = new Subject;
39449
- loadCallbacks = [];
39450
- beforeLoadCallbacks = [];
39451
39474
  transformationRenderBlock = undefined;
39452
- url = "";
39453
- isPlaying = false;
39454
- currentTime = 0;
39455
- isStorageUrl = true;
39456
- constructor(board, isStorageUrl, url, events, id = "", extension2) {
39475
+ iconImage;
39476
+ constructor(board, events, miroData, id = "", backgroundColor = "#E5E5EA", icon = PlaceholderImg?.toString() || "") {
39457
39477
  super(board, id);
39458
39478
  this.events = events;
39459
- this.extension = extension2;
39460
- this.linkTo = new LinkTo(this.id, events);
39461
- this.board = board;
39462
- this.isStorageUrl = isStorageUrl;
39463
- if (url) {
39464
- this.applyUrl(url);
39465
- }
39466
- this.transformation = new Transformation(id, events);
39467
- this.linkTo.subject.subscribe(() => {
39479
+ this.miroData = miroData;
39480
+ this.backgroundColor = backgroundColor;
39481
+ this.icon = icon;
39482
+ this.transformation = new Transformation(this.id, this.events);
39483
+ this.transformation.subject.subscribe((_subject) => {
39484
+ this.transformPath();
39468
39485
  this.updateMbr();
39469
39486
  this.subject.publish(this);
39470
39487
  });
39471
- this.transformation.subject.subscribe(this.onTransform);
39472
- this.right = this.left + conf.AUDIO_DIMENSIONS.width;
39473
- this.bottom = this.top + conf.AUDIO_DIMENSIONS.height;
39474
- this.shouldUseCustomRender = true;
39475
- }
39476
- setCurrentTime(time) {
39477
- this.currentTime = time;
39478
- }
39479
- getCurrentTime() {
39480
- return this.currentTime;
39481
- }
39482
- getIsStorageUrl() {
39483
- return this.isStorageUrl;
39484
- }
39485
- onTransform = () => {
39486
39488
  this.updateMbr();
39487
- this.subject.publish(this);
39488
- };
39489
- doOnceBeforeOnLoad = (callback) => {
39490
- this.loadCallbacks.push(callback);
39491
- };
39492
- doOnceOnLoad = (callback) => {
39493
- this.loadCallbacks.push(callback);
39494
- };
39495
- setIsPlaying(isPlaying) {
39496
- this.isPlaying = isPlaying;
39497
- this.shouldRenderOutsideViewRect = isPlaying;
39498
- this.subject.publish(this);
39499
- }
39500
- getIsPlaying() {
39501
- return this.isPlaying;
39489
+ this.loadIconImage();
39502
39490
  }
39503
- applyUrl(url) {
39504
- if (this.isStorageUrl) {
39505
- try {
39506
- const newUrl = new URL(url);
39507
- this.url = `${window.location.origin}${newUrl.pathname}`;
39508
- } catch (_) {}
39491
+ emit(operation) {
39492
+ if (this.events) {
39493
+ const command = new PlaceholderCommand([this], operation);
39494
+ command.apply();
39495
+ this.events.emit(operation, command);
39509
39496
  } else {
39510
- this.url = url;
39511
- }
39512
- }
39513
- setUrl(url) {
39514
- this.emit({
39515
- class: "Audio",
39516
- method: "setUrl",
39517
- item: [this.getId()],
39518
- url
39519
- });
39520
- }
39521
- getStorageId() {
39522
- return this.url.split("/").pop();
39523
- }
39524
- getUrl() {
39525
- return this.url;
39526
- }
39527
- onLoad = async () => {
39528
- this.shootBeforeLoadCallbacks();
39529
- this.updateMbr();
39530
- this.subject.publish(this);
39531
- this.shootLoadCallbacks();
39532
- };
39533
- onError = (_error) => {
39534
- this.updateMbr();
39535
- this.subject.publish(this);
39536
- this.shootLoadCallbacks();
39537
- };
39538
- updateMbr() {
39539
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
39540
- this.left = translateX;
39541
- this.top = translateY;
39542
- this.right = this.left + conf.AUDIO_DIMENSIONS.width * scaleX;
39543
- this.bottom = this.top + conf.AUDIO_DIMENSIONS.height * scaleY;
39544
- }
39545
- render(context) {
39546
- if (this.transformationRenderBlock) {
39547
- return;
39548
- }
39549
- const ctx = context.ctx;
39550
- const radius = 12 * this.transformation.getScale().x;
39551
- ctx.save();
39552
- ctx.globalCompositeOperation = "destination-out";
39553
- ctx.beginPath();
39554
- ctx.moveTo(this.left + radius, this.top);
39555
- ctx.lineTo(this.left + this.getWidth() - radius, this.top);
39556
- ctx.quadraticCurveTo(this.left + this.getWidth(), this.top, this.left + this.getWidth(), this.top + radius);
39557
- ctx.lineTo(this.left + this.getWidth(), this.top + this.getHeight() - radius);
39558
- ctx.quadraticCurveTo(this.left + this.getWidth(), this.top + this.getHeight(), this.left + this.getWidth() - radius, this.top + this.getHeight());
39559
- ctx.lineTo(this.left + radius, this.top + this.getHeight());
39560
- ctx.quadraticCurveTo(this.left, this.top + this.getHeight(), this.left, this.top + this.getHeight() - radius);
39561
- ctx.lineTo(this.left, this.top + radius);
39562
- ctx.quadraticCurveTo(this.left, this.top, this.left + radius, this.top);
39563
- ctx.closePath();
39564
- ctx.fill();
39565
- ctx.restore();
39566
- }
39567
- renderHTML(documentFactory) {
39568
- const div = documentFactory.createElement("audio-item");
39569
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
39570
- const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
39571
- div.id = this.getId();
39572
- div.style.width = `${conf.AUDIO_DIMENSIONS.width}px`;
39573
- div.style.height = `${conf.AUDIO_DIMENSIONS.height}px`;
39574
- div.style.transformOrigin = "top left";
39575
- div.style.transform = transform;
39576
- div.style.position = "absolute";
39577
- div.setAttribute("audio-url", this.getUrl());
39578
- if (this.extension) {
39579
- div.setAttribute("extension", this.extension);
39580
- }
39581
- if (this.isStorageUrl) {
39582
- div.setAttribute("is-storage-url", "true");
39497
+ this.apply(operation);
39583
39498
  }
39584
- div.setAttribute("data-link-to", "");
39585
- return div;
39586
39499
  }
39587
39500
  serialize() {
39588
39501
  return {
39589
- itemType: "Audio",
39590
- url: this.url,
39502
+ itemType: "Placeholder",
39503
+ backgroundColor: this.backgroundColor,
39504
+ icon: this.icon,
39591
39505
  transformation: this.transformation.serialize(),
39592
- isStorageUrl: this.isStorageUrl,
39593
- extension: this.extension
39506
+ miroData: this.miroData
39594
39507
  };
39595
39508
  }
39596
39509
  deserialize(data) {
39597
- if (data.isStorageUrl) {
39598
- this.isStorageUrl = data.isStorageUrl;
39599
- }
39510
+ this.initPath();
39511
+ this.backgroundColor = data.backgroundColor ?? this.backgroundColor;
39512
+ this.icon = data.icon ?? this.icon;
39513
+ this.miroData = data.miroData;
39600
39514
  if (data.transformation) {
39601
39515
  this.transformation.deserialize(data.transformation);
39516
+ this.transformPath();
39602
39517
  }
39603
- if (data.url) {
39604
- this.setUrl(data.url);
39605
- }
39606
- if (data.extension) {
39607
- this.extension = data.extension;
39608
- }
39518
+ this.subject.publish(this);
39519
+ return this;
39520
+ }
39521
+ setId(id) {
39522
+ this.id = id;
39523
+ this.transformation.setId(id);
39609
39524
  return this;
39610
39525
  }
39526
+ getId() {
39527
+ return this.id;
39528
+ }
39611
39529
  apply(op) {
39612
39530
  switch (op.class) {
39531
+ case "Placeholder":
39532
+ this.applyPlaceholder(op);
39533
+ this.updateMbr();
39534
+ break;
39613
39535
  case "Transformation":
39614
39536
  this.transformation.apply(op);
39615
39537
  break;
39616
- case "LinkTo":
39617
- this.linkTo.apply(op);
39538
+ default:
39539
+ return;
39540
+ }
39541
+ this.subject.publish(this);
39542
+ }
39543
+ applyPlaceholder(op) {
39544
+ switch (op.method) {
39545
+ case "setBackgroundColor":
39546
+ this.applyBackgroundColor(op.backgroundColor);
39618
39547
  break;
39619
- case "Audio":
39620
- if (op.method === "setUrl") {
39621
- this.applyUrl(op.url);
39622
- }
39623
- this.subject.publish(this);
39548
+ case "setIcon":
39549
+ this.applyIcon(op.icon);
39550
+ break;
39551
+ case "setMiroData":
39552
+ this.applyMiroData(op.miroData);
39624
39553
  break;
39625
39554
  }
39626
39555
  }
39627
- emit(operation) {
39628
- if (this.events) {
39629
- const command = new AudioCommand([this], operation);
39630
- command.apply();
39631
- this.events.emit(operation, command);
39632
- } else {
39633
- this.apply(operation);
39634
- }
39556
+ getBackgroundColor() {
39557
+ return this.backgroundColor;
39635
39558
  }
39636
- setId(id) {
39637
- this.id = id;
39638
- this.transformation.setId(id);
39639
- return this;
39559
+ applyBackgroundColor(backgroundColor) {
39560
+ this.backgroundColor = backgroundColor;
39561
+ this.path.setBackgroundColor(backgroundColor);
39640
39562
  }
39641
- getId() {
39642
- return this.id;
39563
+ setBackgroundColor(backgroundColor) {
39564
+ this.emit({
39565
+ class: "Placeholder",
39566
+ method: "setBackgroundColor",
39567
+ item: [this.getId()],
39568
+ backgroundColor
39569
+ });
39643
39570
  }
39644
- shootLoadCallbacks() {
39645
- while (this.loadCallbacks.length > 0) {
39646
- this.loadCallbacks.shift()(this);
39647
- }
39648
- }
39649
- shootBeforeLoadCallbacks() {
39650
- while (this.beforeLoadCallbacks.length > 0) {
39651
- this.beforeLoadCallbacks.shift()(this);
39652
- }
39653
- }
39654
- getPath() {
39655
- const { left, top, right, bottom } = this.getMbr();
39656
- const leftTop = new Point(left, top);
39657
- const rightTop = new Point(right, top);
39658
- const rightBottom = new Point(right, bottom);
39659
- const leftBottom = new Point(left, bottom);
39660
- return new Path([
39661
- new Line(leftTop, rightTop),
39662
- new Line(rightTop, rightBottom),
39663
- new Line(rightBottom, leftBottom),
39664
- new Line(leftBottom, leftTop)
39665
- ], true);
39666
- }
39667
- getSnapAnchorPoints() {
39668
- const mbr = this.getMbr();
39669
- const width2 = mbr.getWidth();
39670
- const height2 = mbr.getHeight();
39671
- return [
39672
- new Point(mbr.left + width2 / 2, mbr.top),
39673
- new Point(mbr.left + width2 / 2, mbr.bottom),
39674
- new Point(mbr.left, mbr.top + height2 / 2),
39675
- new Point(mbr.right, mbr.top + height2 / 2)
39676
- ];
39677
- }
39678
- isClosed() {
39679
- return true;
39680
- }
39681
- getRichText() {
39682
- return null;
39683
- }
39684
- getLinkTo() {
39685
- return;
39686
- }
39687
- getExtension() {
39688
- return this.extension;
39689
- }
39690
- download() {
39691
- if (this.extension) {
39692
- const linkElem = conf.documentFactory.createElement("a");
39693
- linkElem.href = this.url;
39694
- linkElem.setAttribute("download", `${this.board.getBoardId()}.${this.extension}`);
39695
- linkElem.click();
39696
- }
39697
- }
39698
- }
39699
- // src/Items/Audio/AudioHelpers.ts
39700
- var uploadAudioToStorage = async (hash, audioBlob, accessToken, boardId) => {
39701
- return new Promise((resolve2, reject) => {
39702
- fetch(`${window.location.origin}/api/v1/media/audio/${boardId}`, {
39703
- method: "POST",
39704
- headers: {
39705
- "Content-Type": audioBlob.type,
39706
- "x-audio-id": hash,
39707
- Authorization: `Bearer ${accessToken}`
39708
- },
39709
- body: audioBlob
39710
- }).then(async (response) => {
39711
- if (response.status !== 200) {
39712
- return catchErrorResponse(response, "audio");
39713
- }
39714
- return response.json();
39715
- }).then((data) => {
39716
- console.log(data);
39717
- resolve2(data.src);
39718
- }).catch((error) => {
39719
- console.error("Media storage error:", error);
39720
- reject(error);
39721
- });
39722
- });
39723
- };
39724
- var prepareAudio = (file, accessToken, boardId) => {
39725
- return new Promise((resolve2, reject) => {
39726
- const audio = document.createElement("audio");
39727
- audio.src = URL.createObjectURL(file);
39728
- audio.onloadedmetadata = () => {
39729
- fileTosha256(file).then((hash) => {
39730
- uploadAudioToStorage(hash, file, accessToken, boardId).then((url) => {
39731
- resolve2(url);
39732
- }).catch(reject);
39733
- }).catch(() => {
39734
- reject(new Error("Failed to generate hash"));
39735
- });
39736
- };
39737
- audio.onerror = () => {
39738
- reject(new Error("Failed to load audio"));
39739
- };
39740
- });
39741
- };
39742
- var calculateAudioPosition = (board, audioItem) => {
39743
- const cameraMbr = board.camera.getMbr();
39744
- const cameraWidth = cameraMbr.getWidth();
39745
- const translateX = cameraMbr.left + cameraWidth * 0.34;
39746
- const translateY = cameraMbr.getCenter().y - audioItem.getHeight() / 2;
39747
- const scale = cameraWidth * 0.32 / audioItem.getWidth();
39748
- return new Matrix2(translateX, translateY, scale, scale);
39749
- };
39750
- // src/Items/Placeholder/Placeholder.ts
39751
- var PlaceholderImg = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
39752
- <path d="M5 11.1L7 9.1L12.5 14.6L16 11.1L19 14.1V5H5V11.1ZM4 3H20C20.2652 3 20.5196 3.10536 20.7071 3.29289C20.8946 3.48043 21 3.73478 21 4V20C21 20.2652 20.8946 20.5196 20.7071 20.7071C20.5196 20.8946 20.2652 21 20 21H4C3.73478 21 3.48043 20.8946 3.29289 20.7071C3.10536 20.5196 3 20.2652 3 20V4C3 3.73478 3.10536 3.48043 3.29289 3.29289C3.48043 3.10536 3.73478 3 4 3ZM15.5 10C15.1022 10 14.7206 9.84196 14.4393 9.56066C14.158 9.27936 14 8.89782 14 8.5C14 8.10218 14.158 7.72064 14.4393 7.43934C14.7206 7.15804 15.1022 7 15.5 7C15.8978 7 16.2794 7.15804 16.5607 7.43934C16.842 7.72064 17 8.10218 17 8.5C17 8.89782 16.842 9.27936 16.5607 9.56066C16.2794 9.84196 15.8978 10 15.5 10Z" fill="white" fill-opacity="0.6"/>
39753
- </svg>`;
39754
-
39755
- class Placeholder extends BaseItem {
39756
- events;
39757
- miroData;
39758
- backgroundColor;
39759
- icon;
39760
- itemType = "Placeholder";
39761
- shapeType = "Rectangle";
39762
- parent = "Board";
39763
- transformation;
39764
- path = Shapes[this.shapeType].path.copy();
39765
- mbr = Shapes[this.shapeType].path.getMbr().copy();
39766
- subject = new Subject;
39767
- transformationRenderBlock = undefined;
39768
- iconImage;
39769
- constructor(board, events, miroData, id = "", backgroundColor = "#E5E5EA", icon = PlaceholderImg?.toString() || "") {
39770
- super(board, id);
39771
- this.events = events;
39772
- this.miroData = miroData;
39773
- this.backgroundColor = backgroundColor;
39774
- this.icon = icon;
39775
- this.transformation = new Transformation(this.id, this.events);
39776
- this.transformation.subject.subscribe((_subject) => {
39777
- this.transformPath();
39778
- this.updateMbr();
39779
- this.subject.publish(this);
39780
- });
39781
- this.updateMbr();
39782
- this.loadIconImage();
39783
- }
39784
- emit(operation) {
39785
- if (this.events) {
39786
- const command = new PlaceholderCommand([this], operation);
39787
- command.apply();
39788
- this.events.emit(operation, command);
39789
- } else {
39790
- this.apply(operation);
39791
- }
39792
- }
39793
- serialize() {
39794
- return {
39795
- itemType: "Placeholder",
39796
- backgroundColor: this.backgroundColor,
39797
- icon: this.icon,
39798
- transformation: this.transformation.serialize(),
39799
- miroData: this.miroData
39800
- };
39801
- }
39802
- deserialize(data) {
39803
- this.initPath();
39804
- this.backgroundColor = data.backgroundColor ?? this.backgroundColor;
39805
- this.icon = data.icon ?? this.icon;
39806
- this.miroData = data.miroData;
39807
- if (data.transformation) {
39808
- this.transformation.deserialize(data.transformation);
39809
- this.transformPath();
39810
- }
39811
- this.subject.publish(this);
39812
- return this;
39813
- }
39814
- setId(id) {
39815
- this.id = id;
39816
- this.transformation.setId(id);
39817
- return this;
39818
- }
39819
- getId() {
39820
- return this.id;
39821
- }
39822
- apply(op) {
39823
- switch (op.class) {
39824
- case "Placeholder":
39825
- this.applyPlaceholder(op);
39826
- this.updateMbr();
39827
- break;
39828
- case "Transformation":
39829
- this.transformation.apply(op);
39830
- break;
39831
- default:
39832
- return;
39833
- }
39834
- this.subject.publish(this);
39835
- }
39836
- applyPlaceholder(op) {
39837
- switch (op.method) {
39838
- case "setBackgroundColor":
39839
- this.applyBackgroundColor(op.backgroundColor);
39840
- break;
39841
- case "setIcon":
39842
- this.applyIcon(op.icon);
39843
- break;
39844
- case "setMiroData":
39845
- this.applyMiroData(op.miroData);
39846
- break;
39847
- }
39848
- }
39849
- getBackgroundColor() {
39850
- return this.backgroundColor;
39851
- }
39852
- applyBackgroundColor(backgroundColor) {
39853
- this.backgroundColor = backgroundColor;
39854
- this.path.setBackgroundColor(backgroundColor);
39855
- }
39856
- setBackgroundColor(backgroundColor) {
39857
- this.emit({
39858
- class: "Placeholder",
39859
- method: "setBackgroundColor",
39860
- item: [this.getId()],
39861
- backgroundColor
39862
- });
39863
- }
39864
- getIcon() {
39865
- return this.icon;
39571
+ getIcon() {
39572
+ return this.icon;
39866
39573
  }
39867
39574
  applyIcon(icon) {
39868
39575
  this.icon = icon;
@@ -40106,100 +39813,374 @@ class ImageItem extends BaseItem {
40106
39813
  this.shootLoadCallbacks();
40107
39814
  };
40108
39815
  onError = (_error) => {
40109
- this.image = getPlaceholderImage(this.board);
39816
+ this.image = getPlaceholderImage(this.board);
39817
+ this.updateMbr();
39818
+ this.subject.publish(this);
39819
+ this.shootLoadCallbacks();
39820
+ };
39821
+ onTransform = () => {
39822
+ this.updateMbr();
39823
+ this.subject.publish(this);
39824
+ };
39825
+ updateMbr() {
39826
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
39827
+ this.left = translateX;
39828
+ this.top = translateY;
39829
+ this.right = this.left + this.image.width * scaleX;
39830
+ this.bottom = this.top + this.image.height * scaleY;
39831
+ }
39832
+ doOnceBeforeOnLoad = (callback) => {
39833
+ this.loadCallbacks.push(callback);
39834
+ };
39835
+ doOnceOnLoad = (callback) => {
39836
+ this.loadCallbacks.push(callback);
39837
+ };
39838
+ setId(id) {
39839
+ this.id = id;
39840
+ this.transformation.setId(id);
39841
+ this.linkTo.setId(id);
39842
+ return this;
39843
+ }
39844
+ getId() {
39845
+ return this.id;
39846
+ }
39847
+ serialize() {
39848
+ return {
39849
+ itemType: "Image",
39850
+ storageLink: this.storageLink,
39851
+ imageDimension: this.imageDimension,
39852
+ transformation: this.transformation.serialize(),
39853
+ linkTo: this.linkTo.serialize()
39854
+ };
39855
+ }
39856
+ setCoordinates() {
39857
+ this.left = this.transformation.matrix.translateX;
39858
+ this.top = this.transformation.matrix.translateY;
39859
+ this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
39860
+ this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
39861
+ this.subject.publish(this);
39862
+ }
39863
+ shootBeforeLoadCallbacks() {
39864
+ while (this.beforeLoadCallbacks.length > 0) {
39865
+ this.beforeLoadCallbacks.shift()(this);
39866
+ }
39867
+ }
39868
+ shootLoadCallbacks() {
39869
+ while (this.loadCallbacks.length > 0) {
39870
+ this.loadCallbacks.shift()(this);
39871
+ }
39872
+ }
39873
+ deserialize(data) {
39874
+ if (data.transformation) {
39875
+ this.transformation.deserialize(data.transformation);
39876
+ }
39877
+ this.linkTo.deserialize(data.linkTo);
39878
+ this.image.onload = () => {
39879
+ this.setCoordinates();
39880
+ this.shootLoadCallbacks();
39881
+ };
39882
+ if (data.storageLink) {
39883
+ this.setStorageLink(data.storageLink);
39884
+ }
39885
+ if (this.image.src) {
39886
+ return this;
39887
+ }
39888
+ this.image = getPlaceholderImage(this.board, data.imageDimension);
39889
+ const storageImage = new Image;
39890
+ storageImage.onload = () => {
39891
+ this.image = storageImage;
39892
+ this.onLoad();
39893
+ };
39894
+ storageImage.onerror = this.onError;
39895
+ storageImage.src = this.storageLink;
39896
+ return this;
39897
+ }
39898
+ emit(operation) {
39899
+ if (this.events) {
39900
+ const command = new ImageCommand([this], operation);
39901
+ command.apply();
39902
+ this.events.emit(operation, command);
39903
+ } else {
39904
+ this.apply(operation);
39905
+ }
39906
+ }
39907
+ setDimensions(dim) {
39908
+ this.imageDimension = dim;
39909
+ }
39910
+ apply(op) {
39911
+ switch (op.class) {
39912
+ case "Transformation":
39913
+ this.transformation.apply(op);
39914
+ break;
39915
+ case "LinkTo":
39916
+ this.linkTo.apply(op);
39917
+ break;
39918
+ case "Image":
39919
+ if (op.data.base64) {
39920
+ this.image.src = op.data.base64;
39921
+ }
39922
+ this.setStorageLink(op.data.storageLink);
39923
+ this.setDimensions(op.data.imageDimension);
39924
+ this.subject.publish(this);
39925
+ break;
39926
+ }
39927
+ }
39928
+ render(context) {
39929
+ if (this.transformationRenderBlock) {
39930
+ return;
39931
+ }
39932
+ const ctx = context.ctx;
39933
+ ctx.save();
39934
+ this.transformation.matrix.applyToContext(ctx);
39935
+ ctx.drawImage(this.image, 0, 0);
39936
+ ctx.restore();
39937
+ if (this.getLinkTo()) {
39938
+ const { top, right } = this.getMbr();
39939
+ this.linkTo.render(context, top, right, this.board.camera.getScale());
39940
+ }
39941
+ }
39942
+ renderHTML(documentFactory) {
39943
+ const div = documentFactory.createElement("image-item");
39944
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
39945
+ const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
39946
+ div.style.backgroundImage = `url(${this.storageLink})`;
39947
+ div.id = this.getId();
39948
+ div.style.width = `${this.imageDimension.width}px`;
39949
+ div.style.height = `${this.imageDimension.height}px`;
39950
+ div.style.transformOrigin = "top left";
39951
+ div.style.transform = transform;
39952
+ div.style.position = "absolute";
39953
+ div.style.backgroundSize = "cover";
39954
+ div.setAttribute("data-link-to", this.linkTo.serialize() || "");
39955
+ if (this.getLinkTo()) {
39956
+ const linkElement = this.linkTo.renderHTML(documentFactory);
39957
+ scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
39958
+ translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
39959
+ div.appendChild(linkElement);
39960
+ }
39961
+ return div;
39962
+ }
39963
+ getPath() {
39964
+ const { left, top, right, bottom } = this.getMbr();
39965
+ const leftTop = new Point(left, top);
39966
+ const rightTop = new Point(right, top);
39967
+ const rightBottom = new Point(right, bottom);
39968
+ const leftBottom = new Point(left, bottom);
39969
+ return new Path([
39970
+ new Line(leftTop, rightTop),
39971
+ new Line(rightTop, rightBottom),
39972
+ new Line(rightBottom, leftBottom),
39973
+ new Line(leftBottom, leftTop)
39974
+ ], true);
39975
+ }
39976
+ getSnapAnchorPoints() {
39977
+ const mbr = this.getMbr();
39978
+ const width2 = mbr.getWidth();
39979
+ const height2 = mbr.getHeight();
39980
+ return [
39981
+ new Point(mbr.left + width2 / 2, mbr.top),
39982
+ new Point(mbr.left + width2 / 2, mbr.bottom),
39983
+ new Point(mbr.left, mbr.top + height2 / 2),
39984
+ new Point(mbr.right, mbr.top + height2 / 2)
39985
+ ];
39986
+ }
39987
+ isClosed() {
39988
+ return true;
39989
+ }
39990
+ getRichText() {
39991
+ return null;
39992
+ }
39993
+ getLinkTo() {
39994
+ return this.linkTo.link;
39995
+ }
39996
+ download() {
39997
+ const linkElem = document.createElement("a");
39998
+ linkElem.href = this.storageLink;
39999
+ linkElem.setAttribute("download", "");
40000
+ linkElem.click();
40001
+ }
40002
+ onRemove() {
40003
+ const storageId = this.getStorageId();
40004
+ if (storageId) {
40005
+ deleteMedia([storageId], this.board.getBoardId());
40006
+ }
40007
+ super.onRemove();
40008
+ }
40009
+ }
40010
+ // src/Items/Audio/Audio.ts
40011
+ class AudioItem extends BaseItem {
40012
+ events;
40013
+ extension;
40014
+ itemType = "Audio";
40015
+ parent = "Board";
40016
+ transformation;
40017
+ linkTo;
40018
+ subject = new Subject;
40019
+ loadCallbacks = [];
40020
+ beforeLoadCallbacks = [];
40021
+ transformationRenderBlock = undefined;
40022
+ url = "";
40023
+ isPlaying = false;
40024
+ currentTime = 0;
40025
+ isStorageUrl = true;
40026
+ constructor(board, isStorageUrl, url, events, id = "", extension2) {
40027
+ super(board, id);
40028
+ this.events = events;
40029
+ this.extension = extension2;
40030
+ this.linkTo = new LinkTo(this.id, events);
40031
+ this.board = board;
40032
+ this.isStorageUrl = isStorageUrl;
40033
+ if (url) {
40034
+ this.applyUrl(url);
40035
+ }
40036
+ this.transformation = new Transformation(id, events);
40037
+ this.linkTo.subject.subscribe(() => {
40038
+ this.updateMbr();
40039
+ this.subject.publish(this);
40040
+ });
40041
+ this.transformation.subject.subscribe(this.onTransform);
40042
+ this.right = this.left + conf.AUDIO_DIMENSIONS.width;
40043
+ this.bottom = this.top + conf.AUDIO_DIMENSIONS.height;
40044
+ this.shouldUseCustomRender = true;
40045
+ }
40046
+ setCurrentTime(time) {
40047
+ this.currentTime = time;
40048
+ }
40049
+ getCurrentTime() {
40050
+ return this.currentTime;
40051
+ }
40052
+ getIsStorageUrl() {
40053
+ return this.isStorageUrl;
40054
+ }
40055
+ onTransform = () => {
40056
+ this.updateMbr();
40057
+ this.subject.publish(this);
40058
+ };
40059
+ doOnceBeforeOnLoad = (callback) => {
40060
+ this.loadCallbacks.push(callback);
40061
+ };
40062
+ doOnceOnLoad = (callback) => {
40063
+ this.loadCallbacks.push(callback);
40064
+ };
40065
+ setIsPlaying(isPlaying) {
40066
+ this.isPlaying = isPlaying;
40067
+ this.shouldRenderOutsideViewRect = isPlaying;
40068
+ this.subject.publish(this);
40069
+ }
40070
+ getIsPlaying() {
40071
+ return this.isPlaying;
40072
+ }
40073
+ applyUrl(url) {
40074
+ if (this.isStorageUrl) {
40075
+ try {
40076
+ const newUrl = new URL(url);
40077
+ this.url = `${window.location.origin}${newUrl.pathname}`;
40078
+ } catch (_) {}
40079
+ } else {
40080
+ this.url = url;
40081
+ }
40082
+ }
40083
+ setUrl(url) {
40084
+ this.emit({
40085
+ class: "Audio",
40086
+ method: "setUrl",
40087
+ item: [this.getId()],
40088
+ url
40089
+ });
40090
+ }
40091
+ getStorageId() {
40092
+ if (!this.isStorageUrl) {
40093
+ return;
40094
+ }
40095
+ return this.url.split("/").pop();
40096
+ }
40097
+ getUrl() {
40098
+ return this.url;
40099
+ }
40100
+ onLoad = async () => {
40101
+ this.shootBeforeLoadCallbacks();
40102
+ this.updateMbr();
40103
+ this.subject.publish(this);
40104
+ this.shootLoadCallbacks();
40105
+ };
40106
+ onError = (_error) => {
40110
40107
  this.updateMbr();
40111
40108
  this.subject.publish(this);
40112
40109
  this.shootLoadCallbacks();
40113
40110
  };
40114
- onTransform = () => {
40115
- this.updateMbr();
40116
- this.subject.publish(this);
40117
- };
40118
40111
  updateMbr() {
40119
40112
  const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
40120
40113
  this.left = translateX;
40121
40114
  this.top = translateY;
40122
- this.right = this.left + this.image.width * scaleX;
40123
- this.bottom = this.top + this.image.height * scaleY;
40115
+ this.right = this.left + conf.AUDIO_DIMENSIONS.width * scaleX;
40116
+ this.bottom = this.top + conf.AUDIO_DIMENSIONS.height * scaleY;
40124
40117
  }
40125
- doOnceBeforeOnLoad = (callback) => {
40126
- this.loadCallbacks.push(callback);
40127
- };
40128
- doOnceOnLoad = (callback) => {
40129
- this.loadCallbacks.push(callback);
40130
- };
40131
- setId(id) {
40132
- this.id = id;
40133
- this.transformation.setId(id);
40134
- this.linkTo.setId(id);
40135
- return this;
40118
+ render(context) {
40119
+ if (this.transformationRenderBlock) {
40120
+ return;
40121
+ }
40122
+ const ctx = context.ctx;
40123
+ const radius = 12 * this.transformation.getScale().x;
40124
+ ctx.save();
40125
+ ctx.globalCompositeOperation = "destination-out";
40126
+ ctx.beginPath();
40127
+ ctx.moveTo(this.left + radius, this.top);
40128
+ ctx.lineTo(this.left + this.getWidth() - radius, this.top);
40129
+ ctx.quadraticCurveTo(this.left + this.getWidth(), this.top, this.left + this.getWidth(), this.top + radius);
40130
+ ctx.lineTo(this.left + this.getWidth(), this.top + this.getHeight() - radius);
40131
+ ctx.quadraticCurveTo(this.left + this.getWidth(), this.top + this.getHeight(), this.left + this.getWidth() - radius, this.top + this.getHeight());
40132
+ ctx.lineTo(this.left + radius, this.top + this.getHeight());
40133
+ ctx.quadraticCurveTo(this.left, this.top + this.getHeight(), this.left, this.top + this.getHeight() - radius);
40134
+ ctx.lineTo(this.left, this.top + radius);
40135
+ ctx.quadraticCurveTo(this.left, this.top, this.left + radius, this.top);
40136
+ ctx.closePath();
40137
+ ctx.fill();
40138
+ ctx.restore();
40136
40139
  }
40137
- getId() {
40138
- return this.id;
40140
+ renderHTML(documentFactory) {
40141
+ const div = documentFactory.createElement("audio-item");
40142
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
40143
+ const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
40144
+ div.id = this.getId();
40145
+ div.style.width = `${conf.AUDIO_DIMENSIONS.width}px`;
40146
+ div.style.height = `${conf.AUDIO_DIMENSIONS.height}px`;
40147
+ div.style.transformOrigin = "top left";
40148
+ div.style.transform = transform;
40149
+ div.style.position = "absolute";
40150
+ div.setAttribute("audio-url", this.getUrl());
40151
+ if (this.extension) {
40152
+ div.setAttribute("extension", this.extension);
40153
+ }
40154
+ if (this.isStorageUrl) {
40155
+ div.setAttribute("is-storage-url", "true");
40156
+ }
40157
+ div.setAttribute("data-link-to", "");
40158
+ return div;
40139
40159
  }
40140
40160
  serialize() {
40141
40161
  return {
40142
- itemType: "Image",
40143
- storageLink: this.storageLink,
40144
- imageDimension: this.imageDimension,
40162
+ itemType: "Audio",
40163
+ url: this.url,
40145
40164
  transformation: this.transformation.serialize(),
40146
- linkTo: this.linkTo.serialize()
40165
+ isStorageUrl: this.isStorageUrl,
40166
+ extension: this.extension
40147
40167
  };
40148
40168
  }
40149
- setCoordinates() {
40150
- this.left = this.transformation.matrix.translateX;
40151
- this.top = this.transformation.matrix.translateY;
40152
- this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
40153
- this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
40154
- this.subject.publish(this);
40155
- }
40156
- shootBeforeLoadCallbacks() {
40157
- while (this.beforeLoadCallbacks.length > 0) {
40158
- this.beforeLoadCallbacks.shift()(this);
40159
- }
40160
- }
40161
- shootLoadCallbacks() {
40162
- while (this.loadCallbacks.length > 0) {
40163
- this.loadCallbacks.shift()(this);
40164
- }
40165
- }
40166
40169
  deserialize(data) {
40170
+ if (data.isStorageUrl) {
40171
+ this.isStorageUrl = data.isStorageUrl;
40172
+ }
40167
40173
  if (data.transformation) {
40168
40174
  this.transformation.deserialize(data.transformation);
40169
40175
  }
40170
- this.linkTo.deserialize(data.linkTo);
40171
- this.image.onload = () => {
40172
- this.setCoordinates();
40173
- this.shootLoadCallbacks();
40174
- };
40175
- if (data.storageLink) {
40176
- this.setStorageLink(data.storageLink);
40176
+ if (data.url) {
40177
+ this.setUrl(data.url);
40177
40178
  }
40178
- if (this.image.src) {
40179
- return this;
40179
+ if (data.extension) {
40180
+ this.extension = data.extension;
40180
40181
  }
40181
- this.image = getPlaceholderImage(this.board, data.imageDimension);
40182
- const storageImage = new Image;
40183
- storageImage.onload = () => {
40184
- this.image = storageImage;
40185
- this.onLoad();
40186
- };
40187
- storageImage.onerror = this.onError;
40188
- storageImage.src = this.storageLink;
40189
40182
  return this;
40190
40183
  }
40191
- emit(operation) {
40192
- if (this.events) {
40193
- const command = new ImageCommand([this], operation);
40194
- command.apply();
40195
- this.events.emit(operation, command);
40196
- } else {
40197
- this.apply(operation);
40198
- }
40199
- }
40200
- setDimensions(dim) {
40201
- this.imageDimension = dim;
40202
- }
40203
40184
  apply(op) {
40204
40185
  switch (op.class) {
40205
40186
  case "Transformation":
@@ -40208,50 +40189,40 @@ class ImageItem extends BaseItem {
40208
40189
  case "LinkTo":
40209
40190
  this.linkTo.apply(op);
40210
40191
  break;
40211
- case "Image":
40212
- if (op.data.base64) {
40213
- this.image.src = op.data.base64;
40192
+ case "Audio":
40193
+ if (op.method === "setUrl") {
40194
+ this.applyUrl(op.url);
40214
40195
  }
40215
- this.setStorageLink(op.data.storageLink);
40216
- this.setDimensions(op.data.imageDimension);
40217
40196
  this.subject.publish(this);
40218
40197
  break;
40219
40198
  }
40220
40199
  }
40221
- render(context) {
40222
- if (this.transformationRenderBlock) {
40223
- return;
40200
+ emit(operation) {
40201
+ if (this.events) {
40202
+ const command = new AudioCommand([this], operation);
40203
+ command.apply();
40204
+ this.events.emit(operation, command);
40205
+ } else {
40206
+ this.apply(operation);
40224
40207
  }
40225
- const ctx = context.ctx;
40226
- ctx.save();
40227
- this.transformation.matrix.applyToContext(ctx);
40228
- ctx.drawImage(this.image, 0, 0);
40229
- ctx.restore();
40230
- if (this.getLinkTo()) {
40231
- const { top, right } = this.getMbr();
40232
- this.linkTo.render(context, top, right, this.board.camera.getScale());
40208
+ }
40209
+ setId(id) {
40210
+ this.id = id;
40211
+ this.transformation.setId(id);
40212
+ return this;
40213
+ }
40214
+ getId() {
40215
+ return this.id;
40216
+ }
40217
+ shootLoadCallbacks() {
40218
+ while (this.loadCallbacks.length > 0) {
40219
+ this.loadCallbacks.shift()(this);
40233
40220
  }
40234
40221
  }
40235
- renderHTML(documentFactory) {
40236
- const div = documentFactory.createElement("image-item");
40237
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
40238
- const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
40239
- div.style.backgroundImage = `url(${this.storageLink})`;
40240
- div.id = this.getId();
40241
- div.style.width = `${this.imageDimension.width}px`;
40242
- div.style.height = `${this.imageDimension.height}px`;
40243
- div.style.transformOrigin = "top left";
40244
- div.style.transform = transform;
40245
- div.style.position = "absolute";
40246
- div.style.backgroundSize = "cover";
40247
- div.setAttribute("data-link-to", this.linkTo.serialize() || "");
40248
- if (this.getLinkTo()) {
40249
- const linkElement = this.linkTo.renderHTML(documentFactory);
40250
- scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
40251
- translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
40252
- div.appendChild(linkElement);
40222
+ shootBeforeLoadCallbacks() {
40223
+ while (this.beforeLoadCallbacks.length > 0) {
40224
+ this.beforeLoadCallbacks.shift()(this);
40253
40225
  }
40254
- return div;
40255
40226
  }
40256
40227
  getPath() {
40257
40228
  const { left, top, right, bottom } = this.getMbr();
@@ -40284,15 +40255,78 @@ class ImageItem extends BaseItem {
40284
40255
  return null;
40285
40256
  }
40286
40257
  getLinkTo() {
40287
- return this.linkTo.link;
40258
+ return;
40259
+ }
40260
+ getExtension() {
40261
+ return this.extension;
40288
40262
  }
40289
40263
  download() {
40290
- const linkElem = document.createElement("a");
40291
- linkElem.href = this.storageLink;
40292
- linkElem.setAttribute("download", "");
40293
- linkElem.click();
40264
+ if (this.extension) {
40265
+ const linkElem = conf.documentFactory.createElement("a");
40266
+ linkElem.href = this.url;
40267
+ linkElem.setAttribute("download", `${this.board.getBoardId()}.${this.extension}`);
40268
+ linkElem.click();
40269
+ }
40270
+ }
40271
+ onRemove() {
40272
+ const storageId = this.getStorageId();
40273
+ if (storageId) {
40274
+ deleteMedia([storageId], this.board.getBoardId());
40275
+ }
40276
+ super.onRemove();
40294
40277
  }
40295
40278
  }
40279
+ // src/Items/Audio/AudioHelpers.ts
40280
+ var uploadAudioToStorage = async (hash, audioBlob, accessToken, boardId) => {
40281
+ return new Promise((resolve2, reject) => {
40282
+ fetch(`${window.location.origin}/api/v1/media/audio/${boardId}`, {
40283
+ method: "POST",
40284
+ headers: {
40285
+ "Content-Type": audioBlob.type,
40286
+ "x-audio-id": hash,
40287
+ Authorization: `Bearer ${accessToken}`
40288
+ },
40289
+ body: audioBlob
40290
+ }).then(async (response) => {
40291
+ if (response.status !== 200) {
40292
+ return catchErrorResponse(response, "audio");
40293
+ }
40294
+ return response.json();
40295
+ }).then((data) => {
40296
+ console.log(data);
40297
+ resolve2(data.src);
40298
+ }).catch((error) => {
40299
+ console.error("Media storage error:", error);
40300
+ reject(error);
40301
+ });
40302
+ });
40303
+ };
40304
+ var prepareAudio = (file, accessToken, boardId) => {
40305
+ return new Promise((resolve2, reject) => {
40306
+ const audio = document.createElement("audio");
40307
+ audio.src = URL.createObjectURL(file);
40308
+ audio.onloadedmetadata = () => {
40309
+ fileTosha256(file).then((hash) => {
40310
+ uploadAudioToStorage(hash, file, accessToken, boardId).then((url) => {
40311
+ resolve2(url);
40312
+ }).catch(reject);
40313
+ }).catch(() => {
40314
+ reject(new Error("Failed to generate hash"));
40315
+ });
40316
+ };
40317
+ audio.onerror = () => {
40318
+ reject(new Error("Failed to load audio"));
40319
+ };
40320
+ });
40321
+ };
40322
+ var calculateAudioPosition = (board, audioItem) => {
40323
+ const cameraMbr = board.camera.getMbr();
40324
+ const cameraWidth = cameraMbr.getWidth();
40325
+ const translateX = cameraMbr.left + cameraWidth * 0.34;
40326
+ const translateY = cameraMbr.getCenter().y - audioItem.getHeight() / 2;
40327
+ const scale = cameraWidth * 0.32 / audioItem.getWidth();
40328
+ return new Matrix2(translateX, translateY, scale, scale);
40329
+ };
40296
40330
  // src/isSafari.ts
40297
40331
  function isSafari() {
40298
40332
  if (typeof navigator === "undefined") {
@@ -52144,9 +52178,8 @@ class Board {
52144
52178
  if (withConnectors) {
52145
52179
  connectors = this.items.getLinkedConnectorsById(item.getId()).map((connector) => connector.getId());
52146
52180
  }
52147
- const shouldClearStorageUsage = item.itemType === "Image" || item.itemType === "Video" && item.getIsStorageUrl() || item.itemType === "Audio" && item.getIsStorageUrl();
52148
- if (shouldClearStorageUsage) {
52149
- deleteMedia([item.getStorageId()], this.boardId);
52181
+ if ("onRemove" in item) {
52182
+ item.onRemove();
52150
52183
  }
52151
52184
  this.emit({
52152
52185
  class: "Board",
@@ -52289,7 +52322,7 @@ class Board {
52289
52322
  const created = this.createItem(this.getNewItemId(), childData);
52290
52323
  const added = this.add(created);
52291
52324
  idsMap[childData.id] = added.getId();
52292
- if (added.itemType === "Connector") {
52325
+ if (added instanceof Connector2) {
52293
52326
  addedConnectors.push({
52294
52327
  item: added,
52295
52328
  data: childData
@@ -52302,7 +52335,7 @@ class Board {
52302
52335
  idsMap[parsedData.data.id] = addedFrame.getId();
52303
52336
  } else {
52304
52337
  const added = this.add(this.createItem(this.getNewItemId(), parsedData));
52305
- if (added.itemType === "Connector") {
52338
+ if (added instanceof Connector2) {
52306
52339
  addedConnectors.push({
52307
52340
  item: added,
52308
52341
  data: parsedData
@@ -52340,10 +52373,10 @@ class Board {
52340
52373
  const createdFrames = {};
52341
52374
  const addItem = (itemData) => {
52342
52375
  const item = this.createItem(itemData.id, itemData);
52343
- if (item.itemType === "Connector") {
52376
+ if (item instanceof Connector2) {
52344
52377
  createdConnectors[itemData.id] = { item, itemData };
52345
52378
  }
52346
- if (item.itemType === "Frame") {
52379
+ if (item instanceof Frame) {
52347
52380
  createdFrames[item.getId()] = { item, itemData };
52348
52381
  }
52349
52382
  this.index.insert(item);
@@ -52375,10 +52408,10 @@ class Board {
52375
52408
  if (Array.isArray(items)) {
52376
52409
  for (const itemData of items) {
52377
52410
  const item = this.createItem(itemData.id, itemData);
52378
- if (item.itemType === "Connector") {
52411
+ if (item instanceof Connector2) {
52379
52412
  createdConnectors[itemData.id] = { item, itemData };
52380
52413
  }
52381
- if (item.itemType === "Frame") {
52414
+ if (item instanceof Frame) {
52382
52415
  createdFrames[item.getId()] = { item, itemData };
52383
52416
  }
52384
52417
  this.index.insert(item);
@@ -52387,7 +52420,7 @@ class Board {
52387
52420
  for (const key in items) {
52388
52421
  const itemData = items[key];
52389
52422
  const item = this.createItem(key, itemData);
52390
- if (item.itemType === "Connector") {
52423
+ if (item instanceof Connector2) {
52391
52424
  createdConnectors[key] = { item, itemData };
52392
52425
  }
52393
52426
  this.index.insert(item);