microboard-temp 0.1.5 → 0.1.7

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.
package/dist/cjs/index.js CHANGED
@@ -2102,13 +2102,18 @@ var exports_src = {};
2102
2102
  __export(exports_src, {
2103
2103
  validateRichTextData: () => validateRichTextData,
2104
2104
  validateItemsMap: () => validateItemsMap,
2105
+ uploadVideoToStorage: () => uploadVideoToStorage,
2106
+ uploadVideo: () => uploadVideo,
2105
2107
  translateElementBy: () => translateElementBy,
2106
2108
  toFiniteNumber: () => toFiniteNumber,
2107
2109
  tempStorage: () => tempStorage2,
2108
2110
  tagByType: () => tagByType,
2109
2111
  sha256: () => sha256,
2110
2112
  scaleElementBy: () => scaleElementBy,
2113
+ rgbToRgba: () => rgbToRgba,
2111
2114
  resetElementScale: () => resetElementScale,
2115
+ quickAddItem: () => quickAddItem,
2116
+ prepareVideo: () => prepareVideo,
2112
2117
  positionRelatively: () => positionRelatively,
2113
2118
  positionAbsolutely: () => positionAbsolutely,
2114
2119
  parsersHTML: () => parsersHTML,
@@ -2122,17 +2127,26 @@ __export(exports_src, {
2122
2127
  isHotkeyPushed: () => isHotkeyPushed,
2123
2128
  isFiniteNumber: () => isFiniteNumber,
2124
2129
  isControlCharacter: () => isControlCharacter,
2130
+ getYouTubeVideoPreview: () => getYouTubeVideoPreview,
2131
+ getYouTubeThumbnail: () => getYouTubeThumbnail,
2132
+ getVideoMetadata: () => getVideoMetadata,
2125
2133
  getTranslationFromHTML: () => getTranslationFromHTML,
2126
2134
  getScaleFromHTML: () => getScaleFromHTML,
2127
2135
  getRandomNumber: () => getRandomNumber,
2136
+ getQuickAddButtons: () => getQuickAddButtons,
2128
2137
  getHotkeyLabel: () => getHotkeyLabel,
2138
+ getControlPointData: () => getControlPointData,
2129
2139
  forceNumberIntoInterval: () => forceNumberIntoInterval,
2130
2140
  fileTosha256: () => fileTosha256,
2131
2141
  decodeHtml: () => decodeHtml,
2132
2142
  cursors: () => defaultCursors,
2143
+ createVideoItem: () => createVideoItem,
2133
2144
  createEvents: () => createEvents,
2134
2145
  conf: () => conf,
2135
2146
  checkHotkeys: () => checkHotkeys,
2147
+ catmullRomInterpolate: () => catmullRomInterpolate,
2148
+ captureFrame: () => captureFrame,
2149
+ VideoItem: () => VideoItem,
2136
2150
  Transformation: () => Transformation,
2137
2151
  Tools: () => Tools,
2138
2152
  SubjectOperation: () => SubjectOperation,
@@ -2158,7 +2172,8 @@ __export(exports_src, {
2158
2172
  Items: () => Items,
2159
2173
  Frame: () => Frame,
2160
2174
  ExportQuality: () => ExportQuality,
2161
- Events: () => Events,
2175
+ Events: () => Events2,
2176
+ DefaultTransformationData: () => DefaultTransformationData,
2162
2177
  CubicBezier: () => CubicBezier,
2163
2178
  ConnectorData: () => ConnectorData2,
2164
2179
  Connector: () => Connector,
@@ -30200,6 +30215,791 @@ class Frame {
30200
30215
  return this.text;
30201
30216
  }
30202
30217
  }
30218
+ // src/Items/Video/VideoCommand.ts
30219
+ class VideoCommand {
30220
+ videos;
30221
+ operation;
30222
+ constructor(videos, operation) {
30223
+ this.videos = videos;
30224
+ this.operation = operation;
30225
+ }
30226
+ apply() {
30227
+ for (const video of this.videos) {
30228
+ video.apply(this.operation);
30229
+ }
30230
+ }
30231
+ revert() {}
30232
+ }
30233
+
30234
+ // src/Items/Video/Video.ts
30235
+ var VIDEO_ICON_SRC = "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 22 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M15 0C15.2652 0 15.5196 0.105357 15.7071 0.292893C15.8946 0.48043 16 0.734784 16 1V5.2L21.213 1.55C21.288 1.49746 21.3759 1.4665 21.4672 1.4605C21.5586 1.4545 21.6498 1.4737 21.731 1.51599C21.8122 1.55829 21.8802 1.62206 21.9276 1.70035C21.9751 1.77865 22.0001 1.86846 22 1.96V14.04C22.0001 14.1315 21.9751 14.2214 21.9276 14.2996C21.8802 14.3779 21.8122 14.4417 21.731 14.484C21.6498 14.5263 21.5586 14.5455 21.4672 14.5395C21.3759 14.5335 21.288 14.5025 21.213 14.45L16 10.8V15C16 15.2652 15.8946 15.5196 15.7071 15.7071C15.5196 15.8946 15.2652 16 15 16H1C0.734784 16 0.48043 15.8946 0.292893 15.7071C0.105357 15.5196 0 15.2652 0 15V1C0 0.734784 0.105357 0.48043 0.292893 0.292893C0.48043 0.105357 0.734784 0 1 0H15ZM14 2H2V14H14V2ZM6.4 4.829C6.47611 4.82879 6.55069 4.8503 6.615 4.891L10.97 7.663C11.0266 7.69917 11.0731 7.749 11.1054 7.80789C11.1376 7.86679 11.1545 7.93285 11.1545 8C11.1545 8.06715 11.1376 8.13321 11.1054 8.19211C11.0731 8.251 11.0266 8.30083 10.97 8.337L6.615 11.11C6.55434 11.1487 6.48438 11.1703 6.41248 11.1725C6.34059 11.1748 6.26941 11.1576 6.20646 11.1228C6.14351 11.088 6.0911 11.0368 6.05477 10.9747C6.01844 10.9127 5.99951 10.8419 6 10.77V5.23C6 5.009 6.18 4.83 6.4 4.83V4.829ZM20 4.84L16 7.64V8.358L20 11.158V4.84Z' fill='%23FFFFFF'/%3E%3C/svg%3E";
30236
+ var videoIcon = conf.documentFactory.createElement("img");
30237
+ videoIcon.src = VIDEO_ICON_SRC;
30238
+ var createPlaceholderImage = (width, height) => {
30239
+ const canvas = conf.documentFactory.createElement("canvas");
30240
+ canvas.width = width;
30241
+ canvas.height = height;
30242
+ const ctx = canvas.getContext("2d");
30243
+ if (ctx) {
30244
+ ctx.fillStyle = "rgba(229, 229, 234, 1)";
30245
+ ctx.fillRect(0, 0, width, height);
30246
+ const iconSize = Math.min(width, height) * 0.3;
30247
+ const iconX = (width - iconSize) / 2;
30248
+ const iconY = (height - iconSize) / 2;
30249
+ ctx.drawImage(videoIcon, iconX, iconY, iconSize * 1.375, iconSize);
30250
+ }
30251
+ const image = new Image;
30252
+ image.src = canvas.toDataURL();
30253
+ return image;
30254
+ };
30255
+
30256
+ class VideoItem extends Mbr {
30257
+ events;
30258
+ id;
30259
+ extension;
30260
+ itemType = "Video";
30261
+ parent = "Board";
30262
+ preview;
30263
+ transformation;
30264
+ linkTo;
30265
+ subject = new Subject;
30266
+ loadCallbacks = [];
30267
+ beforeLoadCallbacks = [];
30268
+ transformationRenderBlock = undefined;
30269
+ url = "";
30270
+ previewUrl = "";
30271
+ isStorageUrl = false;
30272
+ videoDimension;
30273
+ board;
30274
+ isPlaying = false;
30275
+ shouldShowControls = false;
30276
+ playBtnMbr = new Mbr;
30277
+ currentTime = 0;
30278
+ constructor({ url, videoDimension, previewUrl }, board, events2, id = "", extension2 = "mp4") {
30279
+ super();
30280
+ this.events = events2;
30281
+ this.id = id;
30282
+ this.extension = extension2;
30283
+ this.isStorageUrl = !conf.getYouTubeId(url);
30284
+ this.preview = createPlaceholderImage(videoDimension.width, videoDimension.height);
30285
+ this.linkTo = new LinkTo(this.id, events2);
30286
+ this.board = board;
30287
+ if (previewUrl) {
30288
+ this.previewUrl = previewUrl;
30289
+ this.setPreview(this.preview, previewUrl);
30290
+ }
30291
+ this.preview.onload = this.onLoad;
30292
+ this.preview.onerror = this.onError;
30293
+ if (url) {
30294
+ this.setUrl(url);
30295
+ }
30296
+ this.videoDimension = videoDimension;
30297
+ this.transformation = new Transformation(id, events2);
30298
+ this.linkTo.subject.subscribe(() => {
30299
+ this.updateMbr();
30300
+ this.subject.publish(this);
30301
+ });
30302
+ this.transformation.subject.subscribe(this.onTransform);
30303
+ }
30304
+ setCurrentTime(time2) {
30305
+ this.currentTime = time2;
30306
+ }
30307
+ getCurrentTime() {
30308
+ return this.currentTime;
30309
+ }
30310
+ onTransform = () => {
30311
+ this.updateMbr();
30312
+ this.subject.publish(this);
30313
+ };
30314
+ doOnceBeforeOnLoad = (callback) => {
30315
+ this.loadCallbacks.push(callback);
30316
+ };
30317
+ doOnceOnLoad = (callback) => {
30318
+ this.loadCallbacks.push(callback);
30319
+ };
30320
+ getStorageId() {
30321
+ return this.url.split("/").pop();
30322
+ }
30323
+ getIsStorageUrl() {
30324
+ return this.isStorageUrl;
30325
+ }
30326
+ setVideoData({ previewUrl, url }) {
30327
+ this.emit({
30328
+ class: "Video",
30329
+ item: [this.id],
30330
+ method: "updateVideoData",
30331
+ data: { previewUrl, url, videoDimension: this.videoDimension }
30332
+ });
30333
+ }
30334
+ applyVideoData({ previewUrl = "", url = "" }) {
30335
+ this.previewUrl = previewUrl;
30336
+ this.setPreview(this.preview, previewUrl);
30337
+ this.setUrl(url);
30338
+ }
30339
+ setIsPlaying(isPlaying) {
30340
+ this.isPlaying = isPlaying;
30341
+ this.subject.publish(this);
30342
+ }
30343
+ getIsPlaying() {
30344
+ return this.isPlaying;
30345
+ }
30346
+ setShouldShowControls(shouldShowControls) {
30347
+ this.shouldShowControls = shouldShowControls;
30348
+ this.subject.publish(this);
30349
+ }
30350
+ getShouldShowControls() {
30351
+ return this.shouldShowControls;
30352
+ }
30353
+ getPlayBtnMbr() {
30354
+ return this.playBtnMbr;
30355
+ }
30356
+ setUrl(url) {
30357
+ if (this.isStorageUrl) {
30358
+ try {
30359
+ const newUrl = new URL(url);
30360
+ this.url = `${window.location.origin}${newUrl.pathname}`;
30361
+ } catch (_) {}
30362
+ } else {
30363
+ this.url = url;
30364
+ }
30365
+ }
30366
+ setPreview(image, previewUrl) {
30367
+ if (this.isStorageUrl) {
30368
+ try {
30369
+ const newUrl = new URL(previewUrl);
30370
+ image.src = `${window.location.origin}${newUrl.pathname}`;
30371
+ } catch (_) {}
30372
+ } else {
30373
+ image.src = previewUrl;
30374
+ }
30375
+ image.onload = () => {
30376
+ this.preview = image;
30377
+ };
30378
+ }
30379
+ setPreviewImage(image) {
30380
+ this.preview = image;
30381
+ this.preview.onload = this.onLoad;
30382
+ this.preview.onerror = () => {
30383
+ const defaultPreview = new Image;
30384
+ defaultPreview.src = this.getPreviewUrl();
30385
+ this.preview = defaultPreview;
30386
+ this.preview.onload = this.onLoad;
30387
+ this.preview.onerror = this.onError;
30388
+ this.subject.publish(this);
30389
+ };
30390
+ this.subject.publish(this);
30391
+ }
30392
+ getPreviewUrl() {
30393
+ return this.previewUrl;
30394
+ }
30395
+ getUrl() {
30396
+ return this.url;
30397
+ }
30398
+ onLoad = async () => {
30399
+ this.shootBeforeLoadCallbacks();
30400
+ this.updateMbr();
30401
+ this.subject.publish(this);
30402
+ this.shootLoadCallbacks();
30403
+ };
30404
+ onError = (_error) => {
30405
+ this.preview = createPlaceholderImage(this.videoDimension.width, this.videoDimension.height);
30406
+ this.updateMbr();
30407
+ this.subject.publish(this);
30408
+ this.shootLoadCallbacks();
30409
+ };
30410
+ updateMbr() {
30411
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
30412
+ this.left = translateX;
30413
+ this.top = translateY;
30414
+ this.right = this.left + this.videoDimension.width * scaleX;
30415
+ this.bottom = this.top + this.videoDimension.height * scaleY;
30416
+ const playBtnSize = 50;
30417
+ const scaledPlayBtn = playBtnSize * this.transformation.matrix.scaleX;
30418
+ this.playBtnMbr = new Mbr(this.left + this.getWidth() / 2 - scaledPlayBtn / 2, this.top + this.getHeight() / 2 - scaledPlayBtn / 2, this.right - this.getWidth() / 2 + scaledPlayBtn / 2, this.bottom - this.getHeight() / 2 + scaledPlayBtn / 2);
30419
+ }
30420
+ render(context) {
30421
+ if (this.transformationRenderBlock || !this.preview.complete) {
30422
+ return;
30423
+ }
30424
+ const ctx = context.ctx;
30425
+ if (this.isPlaying) {
30426
+ ctx.save();
30427
+ ctx.globalCompositeOperation = "destination-out";
30428
+ ctx.fillRect(this.left, this.top, this.getWidth(), this.getHeight());
30429
+ ctx.restore();
30430
+ return;
30431
+ }
30432
+ ctx.save();
30433
+ this.transformation.matrix.applyToContext(ctx);
30434
+ ctx.drawImage(this.preview, 0, 0);
30435
+ if (this.shouldShowControls && this.previewUrl) {
30436
+ ctx.restore();
30437
+ ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
30438
+ ctx.fillRect(this.left, this.top, this.getWidth(), this.getHeight());
30439
+ const playBtnSize = this.playBtnMbr.getWidth();
30440
+ const left = this.playBtnMbr.left;
30441
+ const top = this.playBtnMbr.top;
30442
+ ctx.fillStyle = "white";
30443
+ ctx.beginPath();
30444
+ ctx.moveTo(left, top);
30445
+ ctx.lineTo(left + playBtnSize, top + playBtnSize / 2);
30446
+ ctx.lineTo(left, top + playBtnSize);
30447
+ ctx.closePath();
30448
+ ctx.fill();
30449
+ }
30450
+ ctx.restore();
30451
+ }
30452
+ renderHTML(documentFactory) {
30453
+ const div = documentFactory.createElement("video-item");
30454
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
30455
+ const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
30456
+ div.style.backgroundImage = this.previewUrl ? `url(${this.previewUrl})` : `url(${createPlaceholderImage(this.videoDimension.width, this.videoDimension.height).src})`;
30457
+ div.id = this.getId();
30458
+ div.style.width = `${this.videoDimension.width}px`;
30459
+ div.style.height = `${this.videoDimension.height}px`;
30460
+ div.style.transformOrigin = "top left";
30461
+ div.style.transform = transform;
30462
+ div.style.position = "absolute";
30463
+ div.style.backgroundSize = "cover";
30464
+ div.setAttribute("video-url", this.getUrl());
30465
+ div.setAttribute("preview-url", this.getPreviewUrl());
30466
+ div.setAttribute("extension", this.extension);
30467
+ div.setAttribute("is-storage-url", this.isStorageUrl ? "1" : "");
30468
+ div.setAttribute("data-link-to", "");
30469
+ return div;
30470
+ }
30471
+ serialize() {
30472
+ return {
30473
+ itemType: "Video",
30474
+ url: this.url,
30475
+ videoDimension: this.videoDimension,
30476
+ transformation: this.transformation.serialize(),
30477
+ isStorageUrl: this.isStorageUrl,
30478
+ previewUrl: this.previewUrl,
30479
+ extension: this.extension
30480
+ };
30481
+ }
30482
+ deserialize(data) {
30483
+ if (data.transformation) {
30484
+ this.transformation.deserialize(data.transformation);
30485
+ }
30486
+ if (data.isStorageUrl) {
30487
+ this.isStorageUrl = data.isStorageUrl;
30488
+ }
30489
+ if (data.url) {
30490
+ this.setUrl(data.url);
30491
+ }
30492
+ if (data.extension) {
30493
+ this.extension = data.extension;
30494
+ }
30495
+ this.preview = createPlaceholderImage(data.videoDimension?.width || 100, data.videoDimension?.height || 100);
30496
+ const storageImage = new Image;
30497
+ storageImage.onload = () => {
30498
+ this.onLoad();
30499
+ };
30500
+ storageImage.onerror = this.onError;
30501
+ if (data.previewUrl) {
30502
+ this.setPreview(storageImage, data.previewUrl);
30503
+ }
30504
+ return this;
30505
+ }
30506
+ apply(op) {
30507
+ switch (op.class) {
30508
+ case "Transformation":
30509
+ this.transformation.apply(op);
30510
+ break;
30511
+ case "LinkTo":
30512
+ this.linkTo.apply(op);
30513
+ break;
30514
+ case "Video":
30515
+ if (op.method === "updateVideoData") {
30516
+ this.applyVideoData({
30517
+ url: op.data.url,
30518
+ previewUrl: op.data.previewUrl
30519
+ });
30520
+ }
30521
+ this.subject.publish(this);
30522
+ break;
30523
+ }
30524
+ }
30525
+ emit(operation) {
30526
+ if (this.events) {
30527
+ const command = new VideoCommand([this], operation);
30528
+ command.apply();
30529
+ this.events.emit(operation, command);
30530
+ } else {
30531
+ this.apply(operation);
30532
+ }
30533
+ }
30534
+ setId(id) {
30535
+ this.id = id;
30536
+ this.transformation.setId(id);
30537
+ return this;
30538
+ }
30539
+ getId() {
30540
+ return this.id;
30541
+ }
30542
+ shootLoadCallbacks() {
30543
+ while (this.loadCallbacks.length > 0) {
30544
+ this.loadCallbacks.shift()(this);
30545
+ }
30546
+ }
30547
+ shootBeforeLoadCallbacks() {
30548
+ while (this.beforeLoadCallbacks.length > 0) {
30549
+ this.beforeLoadCallbacks.shift()(this);
30550
+ }
30551
+ }
30552
+ getPath() {
30553
+ const { left, top, right, bottom } = this.getMbr();
30554
+ const leftTop = new Point(left, top);
30555
+ const rightTop = new Point(right, top);
30556
+ const rightBottom = new Point(right, bottom);
30557
+ const leftBottom = new Point(left, bottom);
30558
+ return new Path([
30559
+ new Line(leftTop, rightTop),
30560
+ new Line(rightTop, rightBottom),
30561
+ new Line(rightBottom, leftBottom),
30562
+ new Line(leftBottom, leftTop)
30563
+ ], true);
30564
+ }
30565
+ getSnapAnchorPoints() {
30566
+ const mbr = this.getMbr();
30567
+ const width = mbr.getWidth();
30568
+ const height = mbr.getHeight();
30569
+ return [
30570
+ new Point(mbr.left + width / 2, mbr.top),
30571
+ new Point(mbr.left + width / 2, mbr.bottom),
30572
+ new Point(mbr.left, mbr.top + height / 2),
30573
+ new Point(mbr.right, mbr.top + height / 2)
30574
+ ];
30575
+ }
30576
+ isClosed() {
30577
+ return true;
30578
+ }
30579
+ getRichText() {
30580
+ return null;
30581
+ }
30582
+ getLinkTo() {
30583
+ return;
30584
+ }
30585
+ download() {
30586
+ if (this.isStorageUrl) {
30587
+ const linkElem = document.createElement("a");
30588
+ linkElem.href = this.url;
30589
+ linkElem.setAttribute("download", `${this.board.getBoardId()}.${this.extension}`);
30590
+ linkElem.click();
30591
+ }
30592
+ }
30593
+ }
30594
+ // src/Items/Image/calculatePosition.ts
30595
+ function calculatePosition(boardImage, board) {
30596
+ const viewportMbr = board.camera.getMbr();
30597
+ const viewportWidth = viewportMbr.getWidth();
30598
+ const viewportHeight = viewportMbr.getHeight();
30599
+ const centerPoint = viewportMbr.getCenter();
30600
+ const imageWidth = boardImage.getWidth();
30601
+ const imageHeight = boardImage.getHeight();
30602
+ const prevDimensions = tempStorage2.getImageDimensions();
30603
+ if (prevDimensions) {
30604
+ const scaleX2 = prevDimensions.width / imageWidth;
30605
+ const scaleY2 = prevDimensions.height / imageHeight;
30606
+ const finalScale2 = Math.min(scaleX2, scaleY2);
30607
+ return {
30608
+ scaleX: finalScale2,
30609
+ scaleY: finalScale2,
30610
+ translateX: centerPoint.x - imageWidth * finalScale2 / 2,
30611
+ translateY: centerPoint.y - imageHeight * finalScale2 / 2
30612
+ };
30613
+ }
30614
+ const margin = viewportHeight * 0.05;
30615
+ const viewportWidthWithMargin = viewportWidth - 2 * margin;
30616
+ const viewportHeightWithMargin = viewportHeight - 2 * margin;
30617
+ const scaleX = viewportWidthWithMargin / imageWidth;
30618
+ const scaleY = viewportHeightWithMargin / imageHeight;
30619
+ const scaleToFit = Math.min(scaleX, scaleY);
30620
+ const finalScale = scaleToFit;
30621
+ const scaledImageWidth = imageWidth * finalScale;
30622
+ const scaledImageHeight = imageHeight * finalScale;
30623
+ tempStorage2.setImageDimensions({
30624
+ width: scaledImageWidth,
30625
+ height: scaledImageHeight
30626
+ });
30627
+ const scaledImageCenterX = scaledImageWidth / 2;
30628
+ const scaledImageCenterY = scaledImageHeight / 2;
30629
+ const translateX = centerPoint.x - scaledImageCenterX;
30630
+ const translateY = centerPoint.y - scaledImageCenterY;
30631
+ return { scaleX: finalScale, scaleY: finalScale, translateX, translateY };
30632
+ }
30633
+
30634
+ // src/sha256.ts
30635
+ async function sha256(message) {
30636
+ const msgBuffer = new TextEncoder().encode(message);
30637
+ const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
30638
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
30639
+ const hashHex = hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
30640
+ return hashHex;
30641
+ }
30642
+ async function fileTosha256(file) {
30643
+ const buffer = await file.arrayBuffer();
30644
+ const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
30645
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
30646
+ return hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
30647
+ }
30648
+
30649
+ // src/Items/Image/ImageHelpers.ts
30650
+ var catchErrorResponse = async (response, mediaType) => {
30651
+ if (response.status === 403) {
30652
+ const data = await response.json();
30653
+ let errorBody = conf.i18n.t("toolsPanel.addMedia.limitReached.bodyWithoutLimit");
30654
+ if (!data.isOwnerRequest) {
30655
+ errorBody = conf.i18n.t("toolsPanel.addMedia.limitReached.bodyOwner");
30656
+ } else if (data.currentUsage && data.storageLimit) {
30657
+ errorBody = conf.i18n.t(`toolsPanel.addMedia.limitReached.body.${parseInt(data.storageLimit) < 1e5 ? "basic" : "plus"}`);
30658
+ }
30659
+ conf.notify({
30660
+ variant: "warning",
30661
+ header: conf.i18n.t("toolsPanel.addMedia.limitReached.header"),
30662
+ body: errorBody,
30663
+ button: data.isOwnerRequest && data.storageLimit <= 100 ? {
30664
+ text: conf.i18n.t("toolsPanel.addMedia.upgradeToPlus"),
30665
+ onClick: () => conf.openModal("USER_PLAN_MODAL_ID")
30666
+ } : undefined,
30667
+ duration: 8000
30668
+ });
30669
+ } else if (response.status === 413) {
30670
+ const data = await response.json();
30671
+ let errorBody = conf.i18n.t("toolsPanel.addMedia.tooLarge.bodyWithoutLimit");
30672
+ let isBasicPlan = false;
30673
+ if (data.fileSizeLimit && data.fileSize) {
30674
+ if (mediaType === "image") {
30675
+ isBasicPlan = parseInt(data.fileSizeLimit) < 20;
30676
+ errorBody = conf.i18n.t(`toolsPanel.addMedia.tooLarge.imageBody.${isBasicPlan ? "basic" : "plus"}`);
30677
+ } else {
30678
+ isBasicPlan = parseInt(data.fileSizeLimit) < 1000;
30679
+ errorBody = conf.i18n.t(`toolsPanel.addMedia.tooLarge.audioOrVideoBody.${isBasicPlan ? "basic" : "plus"}`);
30680
+ }
30681
+ }
30682
+ conf.notify({
30683
+ variant: "warning",
30684
+ header: conf.i18n.t("toolsPanel.addMedia.tooLarge.header"),
30685
+ body: errorBody,
30686
+ button: isBasicPlan ? {
30687
+ text: conf.i18n.t("toolsPanel.addMedia.upgradeToPlus"),
30688
+ onClick: () => conf.openModal("USER_PLAN_MODAL_ID")
30689
+ } : undefined,
30690
+ duration: 4000
30691
+ });
30692
+ } else if (response.status === 401) {
30693
+ conf.openModal("MEDIA_UNAVAILABLE_MODAL_ID");
30694
+ } else if (response.status === 415) {
30695
+ conf.notify({
30696
+ variant: "warning",
30697
+ header: conf.i18n.t("toolsPanel.addMedia.unsupportedFormat.header"),
30698
+ body: conf.i18n.t("toolsPanel.addMedia.unsupportedFormat.body"),
30699
+ duration: 4000
30700
+ });
30701
+ } else {
30702
+ conf.notify({
30703
+ variant: "error",
30704
+ header: conf.i18n.t("toolsPanel.addMedia.unhandled.header"),
30705
+ body: conf.i18n.t("toolsPanel.addMedia.unhandled.body"),
30706
+ duration: 4000
30707
+ });
30708
+ }
30709
+ throw new Error(`HTTP status: ${response.status}`);
30710
+ };
30711
+ var catchDuplicateErrorResponse = async (response) => {
30712
+ if (response.status === 403) {
30713
+ conf.notify({
30714
+ variant: "warning",
30715
+ header: conf.i18n.t("toolsPanel.addMedia.limitReached.header"),
30716
+ body: conf.i18n.t("toolsPanel.addMedia.limitReached.duplicateBody"),
30717
+ duration: 4000
30718
+ });
30719
+ } else {
30720
+ conf.notify({
30721
+ variant: "error",
30722
+ header: conf.i18n.t("toolsPanel.addMedia.unhandled.header"),
30723
+ body: conf.i18n.t("toolsPanel.addMedia.unhandled.body"),
30724
+ duration: 4000
30725
+ });
30726
+ }
30727
+ throw new Error(`HTTP status: ${response.status}`);
30728
+ };
30729
+ var deleteMedia = async (mediaIds, boardId) => {
30730
+ fetch(`${window?.location.origin}/api/v1/media/usage/${boardId}`, {
30731
+ method: "POST",
30732
+ headers: {
30733
+ "content-type": "application/json"
30734
+ },
30735
+ body: JSON.stringify({ mediaIds, shouldIncrease: false })
30736
+ }).catch((error) => {
30737
+ console.error("Media storage error:", error);
30738
+ });
30739
+ };
30740
+ var updateMediaUsage = async (mediaIds, boardId) => {
30741
+ try {
30742
+ const response = await fetch(`${window?.location.origin}/api/v1/media/usage/${boardId}`, {
30743
+ method: "POST",
30744
+ headers: {
30745
+ "Content-Type": "application/json"
30746
+ },
30747
+ body: JSON.stringify({ mediaIds, shouldIncrease: true })
30748
+ });
30749
+ if (response.status !== 200) {
30750
+ await catchDuplicateErrorResponse(response);
30751
+ return false;
30752
+ }
30753
+ return true;
30754
+ } catch (error) {
30755
+ console.error("Media storage error:", error);
30756
+ return false;
30757
+ }
30758
+ };
30759
+ var uploadToTheStorage = async (hash, dataURL, accessToken, boardId) => {
30760
+ return new Promise((resolve, reject) => {
30761
+ const base64String = dataURL.split(",")[1];
30762
+ const mimeType = dataURL.split(",")[0].split(":")[1].split(";")[0];
30763
+ const binaryString = window.atob(base64String);
30764
+ const bytes = Uint8Array.from(binaryString, (char) => char.charCodeAt(0));
30765
+ const blob = new Blob([bytes], { type: mimeType });
30766
+ fetch(`${window?.location.origin}/api/v1/media/image/${boardId}`, {
30767
+ method: "POST",
30768
+ headers: {
30769
+ "Content-Type": mimeType,
30770
+ "X-Image-Id": hash,
30771
+ Authorization: `Bearer ${accessToken}`
30772
+ },
30773
+ body: blob
30774
+ }).then(async (response) => {
30775
+ if (response.status !== 200) {
30776
+ return catchErrorResponse(response, "image");
30777
+ }
30778
+ return response.json();
30779
+ }).then((data) => {
30780
+ resolve(data.src);
30781
+ }).catch((error) => {
30782
+ console.error("Media storage error:", error);
30783
+ reject(error);
30784
+ });
30785
+ });
30786
+ };
30787
+ var resizeAndConvertToPng = async (inp) => {
30788
+ return new Promise((resolve, reject) => {
30789
+ if (typeof inp !== "string") {
30790
+ return reject("Can't process such input");
30791
+ }
30792
+ const base64String = inp;
30793
+ const image = new Image;
30794
+ image.src = base64String;
30795
+ image.onerror = () => {
30796
+ return reject("Failed to load image");
30797
+ };
30798
+ if (base64String.startsWith("data:image/svg+xml")) {
30799
+ image.onload = async () => {
30800
+ const parser = conf.getDOMParser();
30801
+ const svgDoc = parser.parseFromString(atob(base64String.split(",")[1]), "image/svg+xml");
30802
+ const svgElement = svgDoc.documentElement;
30803
+ svgElement.removeAttribute("width");
30804
+ svgElement.removeAttribute("height");
30805
+ if (!svgElement.getAttribute("viewBox")) {
30806
+ svgElement.setAttribute("viewBox", `0 0 ${image.width} ${image.height}`);
30807
+ }
30808
+ svgElement.setAttribute("width", `${image.width}`);
30809
+ svgElement.setAttribute("height", `${image.height}`);
30810
+ svgElement.setAttribute("preserveAspectRatio", "xMidYMid meet");
30811
+ const newSvgString = new XMLSerializer().serializeToString(svgElement);
30812
+ const newBase64 = `data:image/svg+xml;base64,${btoa(newSvgString)}`;
30813
+ sha256(newBase64).then((hash) => {
30814
+ resolve({
30815
+ dataURL: newBase64,
30816
+ width: image.width,
30817
+ height: image.height,
30818
+ hash: `${hash}.svg`
30819
+ });
30820
+ }).catch(() => {
30821
+ return reject(new Error("Failed to generate hash"));
30822
+ });
30823
+ };
30824
+ } else {
30825
+ image.onload = async () => {
30826
+ const canvas = document.createElement("canvas");
30827
+ const context = canvas.getContext("2d");
30828
+ if (!context) {
30829
+ return reject("Failed to get canvas context");
30830
+ }
30831
+ const { width, height } = image;
30832
+ const scale = 1920 / Math.max(width, height);
30833
+ const canvasWidth = width > 1920 || height > 1920 ? width * scale : width;
30834
+ const canvasHeight = width > 1920 || height > 1920 ? height * scale : height;
30835
+ canvas.width = canvasWidth;
30836
+ canvas.height = canvasHeight;
30837
+ context.drawImage(image, 0, 0, canvasWidth, canvasHeight);
30838
+ const dataURL = canvas.toDataURL("image/webp");
30839
+ sha256(dataURL).then((hash) => {
30840
+ resolve({
30841
+ dataURL,
30842
+ width: canvasWidth,
30843
+ height: canvasHeight,
30844
+ hash
30845
+ });
30846
+ }).catch(() => {
30847
+ return reject(new Error("Failed to generate hash"));
30848
+ });
30849
+ };
30850
+ }
30851
+ });
30852
+ };
30853
+ var prepareImage = (inp, accessToken, boardId) => resizeAndConvertToPng(inp).then(({ width, height, dataURL, hash }) => {
30854
+ return uploadToTheStorage(hash, dataURL, accessToken, boardId).then((src) => {
30855
+ return {
30856
+ imageDimension: { width, height },
30857
+ base64: dataURL,
30858
+ storageLink: src
30859
+ };
30860
+ });
30861
+ });
30862
+
30863
+ // src/Items/Video/VideoHelpers.ts
30864
+ var uploadVideoToStorage = async (hash, videoBlob, accessToken, boardId) => {
30865
+ return new Promise((resolve, reject) => {
30866
+ fetch(`${window.location.origin}/api/v1/media/video/${boardId}`, {
30867
+ method: "POST",
30868
+ headers: {
30869
+ "Content-Type": videoBlob.type,
30870
+ "x-video-id": hash,
30871
+ Authorization: `Bearer ${accessToken}`
30872
+ },
30873
+ body: videoBlob
30874
+ }).then(async (response) => {
30875
+ if (response.status !== 200) {
30876
+ return catchErrorResponse(response, "video");
30877
+ }
30878
+ return response.json();
30879
+ }).then((data) => {
30880
+ resolve(data.src);
30881
+ }).catch((error) => {
30882
+ console.error("Media storage error:", error);
30883
+ reject(error);
30884
+ });
30885
+ });
30886
+ };
30887
+ var getVideoMetadata = (file) => {
30888
+ return new Promise((resolve, reject) => {
30889
+ const video = document.createElement("video");
30890
+ video.preload = "metadata";
30891
+ video.onloadedmetadata = () => {
30892
+ const { videoWidth: width, videoHeight: height } = video;
30893
+ URL.revokeObjectURL(video.src);
30894
+ resolve({ width, height });
30895
+ };
30896
+ video.onerror = () => {
30897
+ URL.revokeObjectURL(video.src);
30898
+ reject(new Error("Failed to load video metadata"));
30899
+ };
30900
+ video.src = URL.createObjectURL(file);
30901
+ });
30902
+ };
30903
+ var createVideoItem = (board, extension2, videoData, onLoadCb) => {
30904
+ const video = new VideoItem(videoData, board, board.events, "", extension2);
30905
+ video.doOnceBeforeOnLoad(() => {
30906
+ const { scaleX, scaleY, translateX, translateY } = calculatePosition(video, board);
30907
+ video.transformation.applyTranslateTo(translateX, translateY);
30908
+ video.transformation.applyScaleTo(scaleX, scaleY);
30909
+ video.updateMbr();
30910
+ const boardVideo = board.add(video);
30911
+ board.selection.removeAll();
30912
+ board.selection.add(boardVideo);
30913
+ onLoadCb(boardVideo);
30914
+ });
30915
+ };
30916
+ var prepareVideo = (file, accessToken, boardId) => {
30917
+ return new Promise((resolve, reject) => {
30918
+ const video = document.createElement("video");
30919
+ video.src = URL.createObjectURL(file);
30920
+ video.onloadedmetadata = () => {
30921
+ video.onseeked = () => {
30922
+ video.onseeked = null;
30923
+ prepareImage(captureFrame(0.1, video)?.src, accessToken, boardId).then((imageData) => {
30924
+ fileTosha256(file).then((hash) => {
30925
+ uploadVideoToStorage(hash, file, accessToken, boardId).then((url) => {
30926
+ resolve({
30927
+ url,
30928
+ previewUrl: imageData.storageLink
30929
+ });
30930
+ }).catch(reject);
30931
+ }).catch(() => {
30932
+ reject(new Error("Failed to generate hash"));
30933
+ });
30934
+ }).catch(() => reject(new Error("Failed to load video preview")));
30935
+ };
30936
+ video.currentTime = 0.1;
30937
+ };
30938
+ video.onerror = () => {
30939
+ reject(new Error("Failed to load video"));
30940
+ };
30941
+ });
30942
+ };
30943
+ var getYouTubeVideoPreview = (youtubeUrl) => {
30944
+ return new Promise((resolve, reject) => {
30945
+ const preview = document.createElement("img");
30946
+ preview.src = youtubeUrl;
30947
+ preview.onload = () => {
30948
+ resolve(preview);
30949
+ };
30950
+ preview.onerror = () => {
30951
+ reject(new Error("Failed to load preview"));
30952
+ };
30953
+ });
30954
+ };
30955
+ var getYouTubeThumbnail = (videoId, quality = "maxres") => {
30956
+ const qualities = {
30957
+ maxres: "maxresdefault",
30958
+ sd: "sddefault",
30959
+ hq: "hqdefault",
30960
+ mq: "mqdefault",
30961
+ default: "default"
30962
+ };
30963
+ return `https://img.youtube.com/vi/${videoId}/${qualities[quality]}.jpg`;
30964
+ };
30965
+ var captureFrame = (frameTime, video) => {
30966
+ video.currentTime = frameTime;
30967
+ const canvas = document.createElement("canvas");
30968
+ canvas.width = video.videoWidth;
30969
+ canvas.height = video.videoHeight;
30970
+ const ctx = canvas.getContext("2d");
30971
+ if (ctx) {
30972
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
30973
+ const frame = new Image;
30974
+ frame.src = canvas.toDataURL();
30975
+ return frame;
30976
+ } else {
30977
+ return null;
30978
+ }
30979
+ };
30980
+ // src/Items/Video/uploadVideo.ts
30981
+ function uploadVideo(file, board, notify2, extension2, accessToken) {
30982
+ getVideoMetadata(file).then((dimension) => {
30983
+ const onLoadCb = (videoItem) => {
30984
+ const notificationId = notify2({
30985
+ variant: "info",
30986
+ header: conf.i18n.t("toolsPanel.addMedia.loading"),
30987
+ body: "",
30988
+ duration: 1e5,
30989
+ loader: "MediaLoader"
30990
+ });
30991
+ prepareVideo(file, accessToken, board.getBoardId()).then((urls) => {
30992
+ videoItem.setVideoData(urls);
30993
+ }).catch((er) => {
30994
+ board.remove(videoItem);
30995
+ console.error("Could not create video:", er);
30996
+ }).finally(() => conf.disMissNotification(notificationId));
30997
+ };
30998
+ createVideoItem(board, extension2, { videoDimension: dimension }, onLoadCb);
30999
+ }).catch((er) => {
31000
+ console.error("Could not create video:", er);
31001
+ });
31002
+ }
30203
31003
  // src/Items/Comment/CommentCommand.ts
30204
31004
  class CommentCommand {
30205
31005
  comment;
@@ -31490,70 +32290,6 @@ class AudioItem extends Mbr {
31490
32290
  }
31491
32291
  }
31492
32292
  }
31493
- // src/sha256.ts
31494
- async function sha256(message) {
31495
- const msgBuffer = new TextEncoder().encode(message);
31496
- const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
31497
- const hashArray = Array.from(new Uint8Array(hashBuffer));
31498
- const hashHex = hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
31499
- return hashHex;
31500
- }
31501
- async function fileTosha256(file) {
31502
- const buffer = await file.arrayBuffer();
31503
- const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
31504
- const hashArray = Array.from(new Uint8Array(hashBuffer));
31505
- return hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
31506
- }
31507
-
31508
- // src/Items/Image/ImageHelpers.ts
31509
- var catchDuplicateErrorResponse = async (response) => {
31510
- if (response.status === 403) {
31511
- conf.notify({
31512
- variant: "warning",
31513
- header: conf.i18n.t("toolsPanel.addMedia.limitReached.header"),
31514
- body: conf.i18n.t("toolsPanel.addMedia.limitReached.duplicateBody"),
31515
- duration: 4000
31516
- });
31517
- } else {
31518
- conf.notify({
31519
- variant: "error",
31520
- header: conf.i18n.t("toolsPanel.addMedia.unhandled.header"),
31521
- body: conf.i18n.t("toolsPanel.addMedia.unhandled.body"),
31522
- duration: 4000
31523
- });
31524
- }
31525
- throw new Error(`HTTP status: ${response.status}`);
31526
- };
31527
- var deleteMedia = async (mediaIds, boardId) => {
31528
- fetch(`${window?.location.origin}/api/v1/media/usage/${boardId}`, {
31529
- method: "POST",
31530
- headers: {
31531
- "content-type": "application/json"
31532
- },
31533
- body: JSON.stringify({ mediaIds, shouldIncrease: false })
31534
- }).catch((error) => {
31535
- console.error("Media storage error:", error);
31536
- });
31537
- };
31538
- var updateMediaUsage = async (mediaIds, boardId) => {
31539
- try {
31540
- const response = await fetch(`${window?.location.origin}/api/v1/media/usage/${boardId}`, {
31541
- method: "POST",
31542
- headers: {
31543
- "Content-Type": "application/json"
31544
- },
31545
- body: JSON.stringify({ mediaIds, shouldIncrease: true })
31546
- });
31547
- if (response.status !== 200) {
31548
- await catchDuplicateErrorResponse(response);
31549
- return false;
31550
- }
31551
- return true;
31552
- } catch (error) {
31553
- console.error("Media storage error:", error);
31554
- return false;
31555
- }
31556
- };
31557
32293
  // src/Items/Drawing/DrawingCommand.ts
31558
32294
  class DrawingCommand {
31559
32295
  item;
@@ -33406,382 +34142,6 @@ class Sticker {
33406
34142
  return this.linkTo.link;
33407
34143
  }
33408
34144
  }
33409
- // src/Items/Video/VideoCommand.ts
33410
- class VideoCommand {
33411
- videos;
33412
- operation;
33413
- constructor(videos, operation) {
33414
- this.videos = videos;
33415
- this.operation = operation;
33416
- }
33417
- apply() {
33418
- for (const video of this.videos) {
33419
- video.apply(this.operation);
33420
- }
33421
- }
33422
- revert() {}
33423
- }
33424
-
33425
- // src/Items/Video/Video.ts
33426
- var VIDEO_ICON_SRC = "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 22 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M15 0C15.2652 0 15.5196 0.105357 15.7071 0.292893C15.8946 0.48043 16 0.734784 16 1V5.2L21.213 1.55C21.288 1.49746 21.3759 1.4665 21.4672 1.4605C21.5586 1.4545 21.6498 1.4737 21.731 1.51599C21.8122 1.55829 21.8802 1.62206 21.9276 1.70035C21.9751 1.77865 22.0001 1.86846 22 1.96V14.04C22.0001 14.1315 21.9751 14.2214 21.9276 14.2996C21.8802 14.3779 21.8122 14.4417 21.731 14.484C21.6498 14.5263 21.5586 14.5455 21.4672 14.5395C21.3759 14.5335 21.288 14.5025 21.213 14.45L16 10.8V15C16 15.2652 15.8946 15.5196 15.7071 15.7071C15.5196 15.8946 15.2652 16 15 16H1C0.734784 16 0.48043 15.8946 0.292893 15.7071C0.105357 15.5196 0 15.2652 0 15V1C0 0.734784 0.105357 0.48043 0.292893 0.292893C0.48043 0.105357 0.734784 0 1 0H15ZM14 2H2V14H14V2ZM6.4 4.829C6.47611 4.82879 6.55069 4.8503 6.615 4.891L10.97 7.663C11.0266 7.69917 11.0731 7.749 11.1054 7.80789C11.1376 7.86679 11.1545 7.93285 11.1545 8C11.1545 8.06715 11.1376 8.13321 11.1054 8.19211C11.0731 8.251 11.0266 8.30083 10.97 8.337L6.615 11.11C6.55434 11.1487 6.48438 11.1703 6.41248 11.1725C6.34059 11.1748 6.26941 11.1576 6.20646 11.1228C6.14351 11.088 6.0911 11.0368 6.05477 10.9747C6.01844 10.9127 5.99951 10.8419 6 10.77V5.23C6 5.009 6.18 4.83 6.4 4.83V4.829ZM20 4.84L16 7.64V8.358L20 11.158V4.84Z' fill='%23FFFFFF'/%3E%3C/svg%3E";
33427
- var videoIcon = conf.documentFactory.createElement("img");
33428
- videoIcon.src = VIDEO_ICON_SRC;
33429
- var createPlaceholderImage = (width2, height2) => {
33430
- const canvas = conf.documentFactory.createElement("canvas");
33431
- canvas.width = width2;
33432
- canvas.height = height2;
33433
- const ctx = canvas.getContext("2d");
33434
- if (ctx) {
33435
- ctx.fillStyle = "rgba(229, 229, 234, 1)";
33436
- ctx.fillRect(0, 0, width2, height2);
33437
- const iconSize = Math.min(width2, height2) * 0.3;
33438
- const iconX = (width2 - iconSize) / 2;
33439
- const iconY = (height2 - iconSize) / 2;
33440
- ctx.drawImage(videoIcon, iconX, iconY, iconSize * 1.375, iconSize);
33441
- }
33442
- const image = new Image;
33443
- image.src = canvas.toDataURL();
33444
- return image;
33445
- };
33446
-
33447
- class VideoItem extends Mbr {
33448
- events;
33449
- id;
33450
- extension;
33451
- itemType = "Video";
33452
- parent = "Board";
33453
- preview;
33454
- transformation;
33455
- linkTo;
33456
- subject = new Subject;
33457
- loadCallbacks = [];
33458
- beforeLoadCallbacks = [];
33459
- transformationRenderBlock = undefined;
33460
- url = "";
33461
- previewUrl = "";
33462
- isStorageUrl = false;
33463
- videoDimension;
33464
- board;
33465
- isPlaying = false;
33466
- shouldShowControls = false;
33467
- playBtnMbr = new Mbr;
33468
- currentTime = 0;
33469
- constructor({ url, videoDimension, previewUrl }, board, events2, id = "", extension2 = "mp4") {
33470
- super();
33471
- this.events = events2;
33472
- this.id = id;
33473
- this.extension = extension2;
33474
- this.isStorageUrl = !conf.getYouTubeId(url);
33475
- this.preview = createPlaceholderImage(videoDimension.width, videoDimension.height);
33476
- this.linkTo = new LinkTo(this.id, events2);
33477
- this.board = board;
33478
- if (previewUrl) {
33479
- this.previewUrl = previewUrl;
33480
- this.setPreview(this.preview, previewUrl);
33481
- }
33482
- this.preview.onload = this.onLoad;
33483
- this.preview.onerror = this.onError;
33484
- if (url) {
33485
- this.setUrl(url);
33486
- }
33487
- this.videoDimension = videoDimension;
33488
- this.transformation = new Transformation(id, events2);
33489
- this.linkTo.subject.subscribe(() => {
33490
- this.updateMbr();
33491
- this.subject.publish(this);
33492
- });
33493
- this.transformation.subject.subscribe(this.onTransform);
33494
- }
33495
- setCurrentTime(time2) {
33496
- this.currentTime = time2;
33497
- }
33498
- getCurrentTime() {
33499
- return this.currentTime;
33500
- }
33501
- onTransform = () => {
33502
- this.updateMbr();
33503
- this.subject.publish(this);
33504
- };
33505
- doOnceBeforeOnLoad = (callback) => {
33506
- this.loadCallbacks.push(callback);
33507
- };
33508
- doOnceOnLoad = (callback) => {
33509
- this.loadCallbacks.push(callback);
33510
- };
33511
- getStorageId() {
33512
- return this.url.split("/").pop();
33513
- }
33514
- getIsStorageUrl() {
33515
- return this.isStorageUrl;
33516
- }
33517
- setVideoData({ previewUrl, url }) {
33518
- this.emit({
33519
- class: "Video",
33520
- item: [this.id],
33521
- method: "updateVideoData",
33522
- data: { previewUrl, url, videoDimension: this.videoDimension }
33523
- });
33524
- }
33525
- applyVideoData({ previewUrl = "", url = "" }) {
33526
- this.previewUrl = previewUrl;
33527
- this.setPreview(this.preview, previewUrl);
33528
- this.setUrl(url);
33529
- }
33530
- setIsPlaying(isPlaying) {
33531
- this.isPlaying = isPlaying;
33532
- this.subject.publish(this);
33533
- }
33534
- getIsPlaying() {
33535
- return this.isPlaying;
33536
- }
33537
- setShouldShowControls(shouldShowControls) {
33538
- this.shouldShowControls = shouldShowControls;
33539
- this.subject.publish(this);
33540
- }
33541
- getShouldShowControls() {
33542
- return this.shouldShowControls;
33543
- }
33544
- getPlayBtnMbr() {
33545
- return this.playBtnMbr;
33546
- }
33547
- setUrl(url) {
33548
- if (this.isStorageUrl) {
33549
- try {
33550
- const newUrl = new URL(url);
33551
- this.url = `${window.location.origin}${newUrl.pathname}`;
33552
- } catch (_) {}
33553
- } else {
33554
- this.url = url;
33555
- }
33556
- }
33557
- setPreview(image, previewUrl) {
33558
- if (this.isStorageUrl) {
33559
- try {
33560
- const newUrl = new URL(previewUrl);
33561
- image.src = `${window.location.origin}${newUrl.pathname}`;
33562
- } catch (_) {}
33563
- } else {
33564
- image.src = previewUrl;
33565
- }
33566
- image.onload = () => {
33567
- this.preview = image;
33568
- };
33569
- }
33570
- setPreviewImage(image) {
33571
- this.preview = image;
33572
- this.preview.onload = this.onLoad;
33573
- this.preview.onerror = () => {
33574
- const defaultPreview = new Image;
33575
- defaultPreview.src = this.getPreviewUrl();
33576
- this.preview = defaultPreview;
33577
- this.preview.onload = this.onLoad;
33578
- this.preview.onerror = this.onError;
33579
- this.subject.publish(this);
33580
- };
33581
- this.subject.publish(this);
33582
- }
33583
- getPreviewUrl() {
33584
- return this.previewUrl;
33585
- }
33586
- getUrl() {
33587
- return this.url;
33588
- }
33589
- onLoad = async () => {
33590
- this.shootBeforeLoadCallbacks();
33591
- this.updateMbr();
33592
- this.subject.publish(this);
33593
- this.shootLoadCallbacks();
33594
- };
33595
- onError = (_error) => {
33596
- this.preview = createPlaceholderImage(this.videoDimension.width, this.videoDimension.height);
33597
- this.updateMbr();
33598
- this.subject.publish(this);
33599
- this.shootLoadCallbacks();
33600
- };
33601
- updateMbr() {
33602
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
33603
- this.left = translateX;
33604
- this.top = translateY;
33605
- this.right = this.left + this.videoDimension.width * scaleX;
33606
- this.bottom = this.top + this.videoDimension.height * scaleY;
33607
- const playBtnSize = 50;
33608
- const scaledPlayBtn = playBtnSize * this.transformation.matrix.scaleX;
33609
- this.playBtnMbr = new Mbr(this.left + this.getWidth() / 2 - scaledPlayBtn / 2, this.top + this.getHeight() / 2 - scaledPlayBtn / 2, this.right - this.getWidth() / 2 + scaledPlayBtn / 2, this.bottom - this.getHeight() / 2 + scaledPlayBtn / 2);
33610
- }
33611
- render(context) {
33612
- if (this.transformationRenderBlock || !this.preview.complete) {
33613
- return;
33614
- }
33615
- const ctx = context.ctx;
33616
- if (this.isPlaying) {
33617
- ctx.save();
33618
- ctx.globalCompositeOperation = "destination-out";
33619
- ctx.fillRect(this.left, this.top, this.getWidth(), this.getHeight());
33620
- ctx.restore();
33621
- return;
33622
- }
33623
- ctx.save();
33624
- this.transformation.matrix.applyToContext(ctx);
33625
- ctx.drawImage(this.preview, 0, 0);
33626
- if (this.shouldShowControls && this.previewUrl) {
33627
- ctx.restore();
33628
- ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
33629
- ctx.fillRect(this.left, this.top, this.getWidth(), this.getHeight());
33630
- const playBtnSize = this.playBtnMbr.getWidth();
33631
- const left = this.playBtnMbr.left;
33632
- const top = this.playBtnMbr.top;
33633
- ctx.fillStyle = "white";
33634
- ctx.beginPath();
33635
- ctx.moveTo(left, top);
33636
- ctx.lineTo(left + playBtnSize, top + playBtnSize / 2);
33637
- ctx.lineTo(left, top + playBtnSize);
33638
- ctx.closePath();
33639
- ctx.fill();
33640
- }
33641
- ctx.restore();
33642
- }
33643
- renderHTML(documentFactory) {
33644
- const div = documentFactory.createElement("video-item");
33645
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
33646
- const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
33647
- div.style.backgroundImage = this.previewUrl ? `url(${this.previewUrl})` : `url(${createPlaceholderImage(this.videoDimension.width, this.videoDimension.height).src})`;
33648
- div.id = this.getId();
33649
- div.style.width = `${this.videoDimension.width}px`;
33650
- div.style.height = `${this.videoDimension.height}px`;
33651
- div.style.transformOrigin = "top left";
33652
- div.style.transform = transform;
33653
- div.style.position = "absolute";
33654
- div.style.backgroundSize = "cover";
33655
- div.setAttribute("video-url", this.getUrl());
33656
- div.setAttribute("preview-url", this.getPreviewUrl());
33657
- div.setAttribute("extension", this.extension);
33658
- div.setAttribute("is-storage-url", this.isStorageUrl ? "1" : "");
33659
- div.setAttribute("data-link-to", "");
33660
- return div;
33661
- }
33662
- serialize() {
33663
- return {
33664
- itemType: "Video",
33665
- url: this.url,
33666
- videoDimension: this.videoDimension,
33667
- transformation: this.transformation.serialize(),
33668
- isStorageUrl: this.isStorageUrl,
33669
- previewUrl: this.previewUrl,
33670
- extension: this.extension
33671
- };
33672
- }
33673
- deserialize(data) {
33674
- if (data.transformation) {
33675
- this.transformation.deserialize(data.transformation);
33676
- }
33677
- if (data.isStorageUrl) {
33678
- this.isStorageUrl = data.isStorageUrl;
33679
- }
33680
- if (data.url) {
33681
- this.setUrl(data.url);
33682
- }
33683
- if (data.extension) {
33684
- this.extension = data.extension;
33685
- }
33686
- this.preview = createPlaceholderImage(data.videoDimension?.width || 100, data.videoDimension?.height || 100);
33687
- const storageImage = new Image;
33688
- storageImage.onload = () => {
33689
- this.onLoad();
33690
- };
33691
- storageImage.onerror = this.onError;
33692
- if (data.previewUrl) {
33693
- this.setPreview(storageImage, data.previewUrl);
33694
- }
33695
- return this;
33696
- }
33697
- apply(op) {
33698
- switch (op.class) {
33699
- case "Transformation":
33700
- this.transformation.apply(op);
33701
- break;
33702
- case "LinkTo":
33703
- this.linkTo.apply(op);
33704
- break;
33705
- case "Video":
33706
- if (op.method === "updateVideoData") {
33707
- this.applyVideoData({
33708
- url: op.data.url,
33709
- previewUrl: op.data.previewUrl
33710
- });
33711
- }
33712
- this.subject.publish(this);
33713
- break;
33714
- }
33715
- }
33716
- emit(operation) {
33717
- if (this.events) {
33718
- const command = new VideoCommand([this], operation);
33719
- command.apply();
33720
- this.events.emit(operation, command);
33721
- } else {
33722
- this.apply(operation);
33723
- }
33724
- }
33725
- setId(id) {
33726
- this.id = id;
33727
- this.transformation.setId(id);
33728
- return this;
33729
- }
33730
- getId() {
33731
- return this.id;
33732
- }
33733
- shootLoadCallbacks() {
33734
- while (this.loadCallbacks.length > 0) {
33735
- this.loadCallbacks.shift()(this);
33736
- }
33737
- }
33738
- shootBeforeLoadCallbacks() {
33739
- while (this.beforeLoadCallbacks.length > 0) {
33740
- this.beforeLoadCallbacks.shift()(this);
33741
- }
33742
- }
33743
- getPath() {
33744
- const { left, top, right, bottom } = this.getMbr();
33745
- const leftTop = new Point(left, top);
33746
- const rightTop = new Point(right, top);
33747
- const rightBottom = new Point(right, bottom);
33748
- const leftBottom = new Point(left, bottom);
33749
- return new Path([
33750
- new Line(leftTop, rightTop),
33751
- new Line(rightTop, rightBottom),
33752
- new Line(rightBottom, leftBottom),
33753
- new Line(leftBottom, leftTop)
33754
- ], true);
33755
- }
33756
- getSnapAnchorPoints() {
33757
- const mbr = this.getMbr();
33758
- const width2 = mbr.getWidth();
33759
- const height2 = mbr.getHeight();
33760
- return [
33761
- new Point(mbr.left + width2 / 2, mbr.top),
33762
- new Point(mbr.left + width2 / 2, mbr.bottom),
33763
- new Point(mbr.left, mbr.top + height2 / 2),
33764
- new Point(mbr.right, mbr.top + height2 / 2)
33765
- ];
33766
- }
33767
- isClosed() {
33768
- return true;
33769
- }
33770
- getRichText() {
33771
- return null;
33772
- }
33773
- getLinkTo() {
33774
- return;
33775
- }
33776
- download() {
33777
- if (this.isStorageUrl) {
33778
- const linkElem = document.createElement("a");
33779
- linkElem.href = this.url;
33780
- linkElem.setAttribute("download", `${this.board.getBoardId()}.${this.extension}`);
33781
- linkElem.click();
33782
- }
33783
- }
33784
- }
33785
34145
  // src/itemFactories.ts
33786
34146
  var itemFactories = {
33787
34147
  Sticker: createSticker,
@@ -46455,7 +46815,7 @@ function createEventsLog(board) {
46455
46815
  return new EventsLog(board);
46456
46816
  }
46457
46817
  // src/Events/Events.ts
46458
- class Events {
46818
+ class Events2 {
46459
46819
  subject;
46460
46820
  log;
46461
46821
  board;
@@ -46581,5 +46941,5 @@ class Events {
46581
46941
  }
46582
46942
  }
46583
46943
  function createEvents(board, connection, lastIndex) {
46584
- return new Events(board, connection, lastIndex);
46944
+ return new Events2(board, connection, lastIndex);
46585
46945
  }