@netless/forge-slide 1.2.0-beta.0 → 1.3.0-beta.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.
package/dist/slide.js CHANGED
@@ -58615,7 +58615,7 @@ var require_lodash = __commonJS2({
58615
58615
  result2.__values__ = wrapper.__values__;
58616
58616
  return result2;
58617
58617
  }
58618
- function chunk7(array, size2, guard) {
58618
+ function chunk8(array, size2, guard) {
58619
58619
  if (guard ? isIterateeCall(array, size2, guard) : size2 === undefined2) {
58620
58620
  size2 = 1;
58621
58621
  } else {
@@ -60487,7 +60487,7 @@ var require_lodash = __commonJS2({
60487
60487
  lodash.bindKey = bindKey;
60488
60488
  lodash.castArray = castArray;
60489
60489
  lodash.chain = chain;
60490
- lodash.chunk = chunk7;
60490
+ lodash.chunk = chunk8;
60491
60491
  lodash.compact = compact;
60492
60492
  lodash.concat = concat;
60493
60493
  lodash.cond = cond;
@@ -60965,6 +60965,7 @@ var require_lodash = __commonJS2({
60965
60965
  }
60966
60966
  });
60967
60967
  var import_paper = __toESM2(require_paper_full(), 1);
60968
+ var import_lodash = __toESM2(require_lodash(), 1);
60968
60969
  function $(e, t, u, x = (h) => h) {
60969
60970
  return e * x(0.5 - t * (0.5 - u));
60970
60971
  }
@@ -61111,6 +61112,8 @@ function me(e, t = {}) {
61111
61112
  function ae(e, t = {}) {
61112
61113
  return ce(me(e, t), t);
61113
61114
  }
61115
+ var elementsUndoOrigin = "elementsUndoOrigin";
61116
+ var backgroundElementsUndoOrigin = "backgroundElementsUndoOrigin";
61114
61117
  function _defineProperty(e, r, t) {
61115
61118
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e;
61116
61119
  }
@@ -61140,6 +61143,12 @@ var ElementModel = class _ElementModel {
61140
61143
  get type() {
61141
61144
  return this.root.get("type");
61142
61145
  }
61146
+ get role() {
61147
+ return this.root.get("role") ?? "normal";
61148
+ }
61149
+ get isBackground() {
61150
+ return this.role === "background";
61151
+ }
61143
61152
  get strokeWidth() {
61144
61153
  return this.root.get(_ElementModel.KEYS.strokeWidth);
61145
61154
  }
@@ -61198,6 +61207,9 @@ var ElementModel = class _ElementModel {
61198
61207
  get isPerformanceEnvironment() {
61199
61208
  return this.isPerformanceMode() && this.shouldUseLocalPoints;
61200
61209
  }
61210
+ isAttached() {
61211
+ return this.root.has(_ElementModel.KEYS.uuid);
61212
+ }
61201
61213
  constructor(root, scope, liveCursor, isPerformanceMode) {
61202
61214
  _defineProperty(this, "shadowEmitter", null);
61203
61215
  _defineProperty(this, "root", void 0);
@@ -61283,16 +61295,12 @@ var ElementModel = class _ElementModel {
61283
61295
  }
61284
61296
  }
61285
61297
  bindObserver() {
61286
- const beforeL = this.root._eH?.l?.length ?? -1;
61287
- const beforeDL = this.root._dEH?.l?.length ?? -1;
61288
61298
  (0, import_forge_room3.removeDeepObserver)(this.root, this.handlePropChange);
61289
61299
  this.subBindObserver();
61290
- const afterRemoveL = this.root._eH?.l?.length ?? -1;
61291
- const afterRemoveDL = this.root._dEH?.l?.length ?? -1;
61292
61300
  this.root.observeDeep(this.handlePropChange);
61293
- const afterAddL = this.root._eH?.l?.length ?? -1;
61294
- const afterAddDL = this.root._dEH?.l?.length ?? -1;
61295
- console.log(`[][][] bindObserver uuid=${this.uuid} doc=${!!this.root.doc} _eH: ${beforeL}->${afterRemoveL}->${afterAddL} _dEH: ${beforeDL}->${afterRemoveDL}->${afterAddDL}`);
61301
+ }
61302
+ mutationOrigin() {
61303
+ return elementsUndoOrigin;
61296
61304
  }
61297
61305
  subBindObserver() {
61298
61306
  }
@@ -61331,62 +61339,81 @@ var ElementModel = class _ElementModel {
61331
61339
  this.item.data.uuid = this.uuid;
61332
61340
  this.item.data.index = this.index;
61333
61341
  this.item.data.type = this.root.get("type");
61342
+ this.item.data.role = this.role;
61334
61343
  this.item.data.ownerId = this.ownerId;
61335
61344
  this.item.applyMatrix = false;
61336
61345
  }
61337
61346
  }
61338
61347
  appendPoints(points) {
61339
61348
  if (this.isPerformanceEnvironment) {
61340
- this.appendPointsPerformance(points);
61349
+ return this.appendPointsPerformance(points);
61341
61350
  } else {
61342
- this.appendPointsDirect(points);
61351
+ return this.appendPointsDirect(points);
61343
61352
  }
61344
61353
  }
61354
+ getPointsArray() {
61355
+ const yArray = this.root.get(_ElementModel.KEYS.points);
61356
+ return yArray instanceof Y.Array ? yArray : null;
61357
+ }
61345
61358
  appendPointsDirect(points) {
61346
- this.root.get(_ElementModel.KEYS.points).push(points);
61359
+ const yArray = this.getPointsArray();
61360
+ if (!yArray) {
61361
+ return false;
61362
+ }
61363
+ yArray.push(points);
61364
+ return true;
61347
61365
  }
61348
61366
  appendPointsPerformance(points) {
61367
+ const yArray = this.getPointsArray();
61368
+ if (!yArray) {
61369
+ return false;
61370
+ }
61349
61371
  this.localPoints = this.localPoints.concat(points);
61350
61372
  this.onVectorUpdate();
61351
61373
  if (this.appendPointsTimer) {
61352
61374
  window.clearTimeout(this.appendPointsTimer);
61353
61375
  }
61354
61376
  if (this.localPoints.length % 80 === 0) {
61355
- const yArray = this.root.get(_ElementModel.KEYS.points);
61356
61377
  yArray?.push(this.localPoints.slice(yArray.length));
61357
61378
  }
61358
61379
  this.appendPointsTimer = window.setTimeout(() => {
61359
61380
  this.appendPointsTimer = null;
61360
61381
  if (this.localPoints.length > 0) {
61361
- const yArray = this.root.get(_ElementModel.KEYS.points);
61362
- yArray?.push(this.localPoints.slice(yArray.length));
61382
+ const nextArray = this.getPointsArray();
61383
+ nextArray?.push(this.localPoints.slice(nextArray.length));
61363
61384
  }
61364
61385
  }, 100);
61386
+ return true;
61365
61387
  }
61366
61388
  setPoints(points) {
61367
61389
  if (this.isPerformanceEnvironment) {
61368
- this.setPointsPerformance(points);
61390
+ return this.setPointsPerformance(points);
61369
61391
  } else {
61370
- this.setPointsDirect(points);
61392
+ return this.setPointsDirect(points);
61371
61393
  }
61372
61394
  }
61373
61395
  setPointsDirect(points) {
61374
61396
  if (this.root.doc) {
61397
+ const yArray = this.getPointsArray();
61398
+ if (!yArray) {
61399
+ return false;
61400
+ }
61375
61401
  this.root.doc.transact(() => {
61376
- const yArray = this.root.get(_ElementModel.KEYS.points);
61377
- if (yArray) {
61378
- yArray.delete(0, yArray.length);
61379
- yArray.push(points);
61380
- }
61381
- });
61402
+ yArray.delete(0, yArray.length);
61403
+ yArray.push(points);
61404
+ }, this.mutationOrigin());
61382
61405
  } else {
61383
- const yArray = this.root.get(_ElementModel.KEYS.points) || new Y.Array();
61406
+ const yArray = this.getPointsArray() || new Y.Array();
61384
61407
  yArray.delete(0, yArray.length);
61385
61408
  yArray.push(points);
61386
61409
  this.root.set(_ElementModel.KEYS.points, yArray);
61387
61410
  }
61411
+ return true;
61388
61412
  }
61389
61413
  setPointsPerformance(points) {
61414
+ if (this.root.doc && !this.getPointsArray()) {
61415
+ return false;
61416
+ }
61390
61417
  this.localPoints = points;
61391
61418
  this.onVectorUpdate();
61392
61419
  if (this.setPointsTimer) {
@@ -61394,25 +61421,33 @@ var ElementModel = class _ElementModel {
61394
61421
  }
61395
61422
  this.setPointsTimer = window.setTimeout(() => {
61396
61423
  if (this.root.doc) {
61424
+ const yArray = this.getPointsArray();
61425
+ if (!yArray) {
61426
+ return;
61427
+ }
61397
61428
  this.root.doc.transact(() => {
61398
- const yArray = this.root.get(_ElementModel.KEYS.points);
61399
- if (yArray) {
61400
- yArray.delete(0, yArray.length);
61401
- yArray.push(points);
61402
- }
61403
- });
61429
+ yArray.delete(0, yArray.length);
61430
+ yArray.push(points);
61431
+ }, this.mutationOrigin());
61404
61432
  } else {
61405
- const yArray = this.root.get(_ElementModel.KEYS.points) || new Y.Array();
61433
+ const yArray = this.getPointsArray() || new Y.Array();
61406
61434
  yArray.delete(0, yArray.length);
61407
61435
  yArray.push(points);
61408
61436
  this.root.set(_ElementModel.KEYS.points, yArray);
61409
61437
  }
61410
61438
  }, 100);
61439
+ return true;
61411
61440
  }
61412
61441
  appendPointsMatrix(matrix) {
61413
61442
  const current = new this.scope.Matrix(this.pointsMatrix);
61414
61443
  const next = matrix.appended(current);
61415
- this.root.set(_ElementModel.KEYS.pointsMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
61444
+ if (this.root.doc) {
61445
+ this.root.doc.transact(() => {
61446
+ this.root.set(_ElementModel.KEYS.pointsMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
61447
+ }, this.mutationOrigin());
61448
+ } else {
61449
+ this.root.set(_ElementModel.KEYS.pointsMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
61450
+ }
61416
61451
  }
61417
61452
  rotateByOffset(angle, centerX, centerY) {
61418
61453
  const current = new this.scope.Matrix(this.pointsMatrix);
@@ -61426,7 +61461,13 @@ var ElementModel = class _ElementModel {
61426
61461
  matrix2.rotate(delta, centerX, centerY);
61427
61462
  next = matrix2.appended(next);
61428
61463
  }
61429
- this.root.set(_ElementModel.KEYS.pointsMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
61464
+ if (this.root.doc) {
61465
+ this.root.doc.transact(() => {
61466
+ this.root.set(_ElementModel.KEYS.pointsMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
61467
+ }, this.mutationOrigin());
61468
+ } else {
61469
+ this.root.set(_ElementModel.KEYS.pointsMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
61470
+ }
61430
61471
  return next.rotation;
61431
61472
  }
61432
61473
  getStyleKeys() {
@@ -61437,7 +61478,6 @@ var ElementModel = class _ElementModel {
61437
61478
  this.subDispose();
61438
61479
  }
61439
61480
  disposeObserver() {
61440
- console.log(`[][][] disposeObserver uuid=${this.uuid}`);
61441
61481
  (0, import_forge_room3.removeDeepObserver)(this.root, this.handlePropChange);
61442
61482
  }
61443
61483
  };
@@ -61476,6 +61516,7 @@ var EditorConfig = class _EditorConfig {
61476
61516
  constructor() {
61477
61517
  _defineProperty2(this, "resizeModel", () => "eight");
61478
61518
  _defineProperty2(this, "uniformScale", () => false);
61519
+ _defineProperty2(this, "translatable", () => true);
61479
61520
  _defineProperty2(this, "controlPoints", []);
61480
61521
  }
61481
61522
  merge(other) {
@@ -61484,6 +61525,7 @@ var EditorConfig = class _EditorConfig {
61484
61525
  const j = RESIZE_MODEL_LEVEL.findIndex((v) => v === other.resizeModel());
61485
61526
  next.resizeModel = () => RESIZE_MODEL_LEVEL[Math.max(i, j)];
61486
61527
  next.uniformScale = this.uniformScale || other.uniformScale;
61528
+ next.translatable = () => this.translatable() && other.translatable();
61487
61529
  next.controlPoints = [];
61488
61530
  return next;
61489
61531
  }
@@ -61512,7 +61554,7 @@ var CurveModel = class extends ElementModel {
61512
61554
  _defineProperty3(this, "debug", false);
61513
61555
  _defineProperty3(this, "clearLocalPointsWhenYPointsChange", false);
61514
61556
  _defineProperty3(this, "shouldUseLocalPoints", true);
61515
- _defineProperty3(this, "localPointsPick", 6);
61557
+ _defineProperty3(this, "localPointsPick", 4);
61516
61558
  if (!this.root.doc || !this.root.has("type")) {
61517
61559
  this.root.set("type", "curve");
61518
61560
  }
@@ -61524,7 +61566,6 @@ var CurveModel = class extends ElementModel {
61524
61566
  return (a2 + b2) / 2;
61525
61567
  }
61526
61568
  parsePoints(points) {
61527
- const hasRealPressure = points.some((p) => p.length >= 3 && p[2] > 0);
61528
61569
  const viewScale = this.scope.project.view.matrix.scaling.x || 1;
61529
61570
  const taper = this.strokeWidth * 5 / viewScale;
61530
61571
  const streamline = Math.min(0.7, 0.7 * viewScale);
@@ -61533,7 +61574,7 @@ var CurveModel = class extends ElementModel {
61533
61574
  smoothing: 0.7,
61534
61575
  thinning: 0.5,
61535
61576
  streamline,
61536
- simulatePressure: !hasRealPressure,
61577
+ simulatePressure: true,
61537
61578
  start: {
61538
61579
  taper,
61539
61580
  cap: true
@@ -61544,36 +61585,13 @@ var CurveModel = class extends ElementModel {
61544
61585
  }
61545
61586
  });
61546
61587
  }
61547
- isPressureValue(value) {
61548
- return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
61549
- }
61550
- pointStride(points) {
61551
- if (points.length >= 3 && points.length % 3 === 0) {
61552
- let hasPressureSlot = false;
61553
- for (let i = 2; i < points.length; i += 3) {
61554
- if (!this.isPressureValue(points[i])) {
61555
- return 2;
61556
- }
61557
- hasPressureSlot = true;
61558
- }
61559
- if (hasPressureSlot) {
61560
- return 3;
61561
- }
61562
- }
61563
- return 2;
61564
- }
61565
61588
  matrixedPoints() {
61566
61589
  const points = this.localPoints.length === 0 ? this.points : this.localPoints;
61567
61590
  const matrix = new this.scope.Matrix(this.pointsMatrix);
61568
- const output = [];
61569
- const stride = this.pointStride(points);
61570
- for (let i = 0, len = points.length; i + 1 < len; i += stride) {
61571
- const p = new this.scope.Point(points[i], points[i + 1]);
61572
- const tp = p.transform(matrix);
61573
- const pressure = stride === 3 ? points[i + 2] ?? 0 : 0;
61574
- output.push([tp.x, tp.y, pressure]);
61575
- }
61576
- return output;
61591
+ return (0, import_lodash.chunk)(points, 2).filter((point) => point.length === 2).map((_ref) => {
61592
+ let [x, y] = _ref;
61593
+ return new this.scope.Point(x, y).transform(matrix);
61594
+ }).map((point) => [point.x, point.y]);
61577
61595
  }
61578
61596
  createPath(points) {
61579
61597
  const path = new this.scope.Path();
@@ -61647,12 +61665,11 @@ var CurveModel = class extends ElementModel {
61647
61665
  liveCursorPoint() {
61648
61666
  const yArray = this.root.get(ElementModel.KEYS.points);
61649
61667
  const points = yArray.toArray();
61650
- const stride = this.pointStride(points);
61651
- if (points.length < stride) {
61668
+ if (points.length < 2) {
61652
61669
  return null;
61653
61670
  }
61654
61671
  const len = points.length;
61655
- const point = new this.scope.Point(points[len - stride], points[len - stride + 1]);
61672
+ const point = new this.scope.Point(points[len - 2], points[len - 1]);
61656
61673
  return point.transform(new this.scope.Matrix(this.pointsMatrix));
61657
61674
  }
61658
61675
  onStyleKeyUpdate(key) {
@@ -61745,7 +61762,7 @@ var SelectorModel = class extends ElementModel {
61745
61762
  onStyleKeyUpdate(_key) {
61746
61763
  }
61747
61764
  };
61748
- var import_lodash = __toESM2(require_lodash(), 1);
61765
+ var import_lodash2 = __toESM2(require_lodash(), 1);
61749
61766
  function _defineProperty5(e, r, t) {
61750
61767
  return (r = _toPropertyKey5(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e;
61751
61768
  }
@@ -61778,7 +61795,7 @@ function serializePath(path) {
61778
61795
  }, []);
61779
61796
  }
61780
61797
  function deserializePath(points, scope, matrix) {
61781
- const segmentGroup = (0, import_lodash.chunk)(points, 6);
61798
+ const segmentGroup = (0, import_lodash2.chunk)(points, 6);
61782
61799
  const path = new scope.Path();
61783
61800
  path.segments = segmentGroup.map((v) => deserializeSegment(v, scope, matrix));
61784
61801
  return path;
@@ -61916,7 +61933,7 @@ var SegmentsModel = class extends ElementModel {
61916
61933
  onStyleKeyUpdate(_key) {
61917
61934
  }
61918
61935
  };
61919
- var import_lodash3 = __toESM2(require_lodash(), 1);
61936
+ var import_lodash4 = __toESM2(require_lodash(), 1);
61920
61937
  function _defineProperty7(e, r, t) {
61921
61938
  return (r = _toPropertyKey7(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e;
61922
61939
  }
@@ -61959,7 +61976,14 @@ var WhiteboardTool = class {
61959
61976
  }
61960
61977
  this.pendingDragEvent = null;
61961
61978
  this.shadowEmitter.setActive(true);
61962
- this.onMouseDown(event);
61979
+ try {
61980
+ this.onMouseDown(event);
61981
+ } catch (error) {
61982
+ this.cancelCurrentAction();
61983
+ this.eventAvailable = false;
61984
+ this.shadowEmitter.setActive(false);
61985
+ throw error;
61986
+ }
61963
61987
  });
61964
61988
  _defineProperty7(this, "flushPendingDrag", () => {
61965
61989
  this.dragRafId = 0;
@@ -61967,7 +61991,14 @@ var WhiteboardTool = class {
61967
61991
  this.lastDragTime = performance.now();
61968
61992
  const event = this.pendingDragEvent;
61969
61993
  this.pendingDragEvent = null;
61970
- this.onMouseDrag(event);
61994
+ try {
61995
+ this.onMouseDrag(event);
61996
+ } catch (error) {
61997
+ this.cancelCurrentAction();
61998
+ this.eventAvailable = false;
61999
+ this.shadowEmitter.setActive(false);
62000
+ throw error;
62001
+ }
61971
62002
  }
61972
62003
  });
61973
62004
  _defineProperty7(this, "onMouseDragSelf", (event) => {
@@ -61978,7 +62009,14 @@ var WhiteboardTool = class {
61978
62009
  if (now - this.lastDragTime >= DRAG_FRAME_MS) {
61979
62010
  this.lastDragTime = now;
61980
62011
  this.pendingDragEvent = null;
61981
- this.onMouseDrag(event);
62012
+ try {
62013
+ this.onMouseDrag(event);
62014
+ } catch (error) {
62015
+ this.cancelCurrentAction();
62016
+ this.eventAvailable = false;
62017
+ this.shadowEmitter.setActive(false);
62018
+ throw error;
62019
+ }
61982
62020
  } else {
61983
62021
  this.pendingDragEvent = event;
61984
62022
  if (!this.dragRafId) {
@@ -61995,11 +62033,26 @@ var WhiteboardTool = class {
61995
62033
  this.dragRafId = 0;
61996
62034
  }
61997
62035
  if (this.pendingDragEvent) {
61998
- this.onMouseDrag(this.pendingDragEvent);
61999
- this.pendingDragEvent = null;
62036
+ try {
62037
+ this.onMouseDrag(this.pendingDragEvent);
62038
+ this.pendingDragEvent = null;
62039
+ } catch (error) {
62040
+ this.pendingDragEvent = null;
62041
+ this.cancelCurrentAction();
62042
+ this.eventAvailable = false;
62043
+ this.shadowEmitter.setActive(false);
62044
+ throw error;
62045
+ }
62046
+ }
62047
+ try {
62048
+ this.onMouseUp(event);
62049
+ } catch (error) {
62050
+ this.cancelCurrentAction();
62051
+ this.eventAvailable = false;
62052
+ throw error;
62053
+ } finally {
62054
+ this.shadowEmitter.setActive(false);
62000
62055
  }
62001
- this.onMouseUp(event);
62002
- this.shadowEmitter.setActive(false);
62003
62056
  });
62004
62057
  this.modelGetter = modelGetter;
62005
62058
  this.enableToolEvent = enableToolEvent;
@@ -62010,8 +62063,10 @@ var WhiteboardTool = class {
62010
62063
  this.tool.onMouseDrag = this.onMouseDragSelf;
62011
62064
  this.tool.onMouseUp = this.onMouseUpSelf;
62012
62065
  }
62066
+ cancelCurrentAction() {
62067
+ }
62013
62068
  };
62014
- var import_lodash2 = __toESM2(require_lodash(), 1);
62069
+ var import_lodash3 = __toESM2(require_lodash(), 1);
62015
62070
  function _defineProperty8(e, r, t) {
62016
62071
  return (r = _toPropertyKey8(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e;
62017
62072
  }
@@ -62060,7 +62115,7 @@ var LineTool = class extends WhiteboardTool {
62060
62115
  const point = path.getPointAt(distance);
62061
62116
  return [point.x, point.y];
62062
62117
  });
62063
- this.elementModel.setPoints((0, import_lodash2.flattenDeep)(points));
62118
+ this.elementModel.setPoints((0, import_lodash3.flattenDeep)(points));
62064
62119
  }
62065
62120
  }
62066
62121
  onMouseUp(_event) {
@@ -62141,7 +62196,7 @@ var LineModel = class extends ElementModel {
62141
62196
  }
62142
62197
  renderLine() {
62143
62198
  const matrix = new this.scope.Matrix(this.pointsMatrix);
62144
- const papperPoints = (0, import_lodash3.chunk)(this.drawPoints, 2).map((item) => {
62199
+ const papperPoints = (0, import_lodash4.chunk)(this.drawPoints, 2).map((item) => {
62145
62200
  return new this.scope.Point(item[0], item[1]).transform(matrix);
62146
62201
  });
62147
62202
  const path = new this.scope.Path();
@@ -62277,7 +62332,7 @@ var LineControlPoint = class {
62277
62332
  const invertedPoint = point.transform(pointsMatrix.inverted());
62278
62333
  const points = this.model["drawPoints"];
62279
62334
  this.position = invertedPoint;
62280
- const clonedPoints = (0, import_lodash3.cloneDeep)(points);
62335
+ const clonedPoints = (0, import_lodash4.cloneDeep)(points);
62281
62336
  clonedPoints[this.options.index * 2] = invertedPoint.x;
62282
62337
  clonedPoints[this.options.index * 2 + 1] = invertedPoint.y;
62283
62338
  this.model.setPoints(clonedPoints);
@@ -62382,7 +62437,6 @@ var PointTextModel = class extends ElementModel {
62382
62437
  if (!this.item) {
62383
62438
  return null;
62384
62439
  }
62385
- console.log("[][][] drawPoints", this.drawPoints);
62386
62440
  const bounds = this.item.internalBounds;
62387
62441
  const matrix = new this.scope.Matrix(this.pointsMatrix);
62388
62442
  const topLeft = new this.scope.Point(this.drawPoints[0], this.drawPoints[1]).transform(matrix);
@@ -62746,8 +62800,7 @@ var RectangleModel = class extends ElementModel {
62746
62800
  onStyleKeyUpdate(_key) {
62747
62801
  }
62748
62802
  };
62749
- var elementsUndoOrigin = "elementsUndoOrigin";
62750
- var import_lodash4 = __toESM2(require_lodash(), 1);
62803
+ var import_lodash5 = __toESM2(require_lodash(), 1);
62751
62804
  function _defineProperty13(e, r, t) {
62752
62805
  return (r = _toPropertyKey13(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e;
62753
62806
  }
@@ -62815,7 +62868,7 @@ var EraserModel = class extends ElementModel {
62815
62868
  return path;
62816
62869
  }
62817
62870
  parsePoints(points) {
62818
- const groupPoints = (0, import_lodash4.chunk)(points, 2);
62871
+ const groupPoints = (0, import_lodash5.chunk)(points, 2);
62819
62872
  return ae(groupPoints, {
62820
62873
  size: this.strokeWidth,
62821
62874
  smoothing: 0.5,
@@ -62833,7 +62886,7 @@ var EraserModel = class extends ElementModel {
62833
62886
  });
62834
62887
  }
62835
62888
  matrixedPoints() {
62836
- const currentPoints = (0, import_lodash4.chunk)(this.drawPoints, 2).slice(this.sliceBegin);
62889
+ const currentPoints = (0, import_lodash5.chunk)(this.drawPoints, 2).slice(this.sliceBegin);
62837
62890
  return currentPoints.map((_ref) => {
62838
62891
  let [x, y] = _ref;
62839
62892
  return new this.scope.Point(x, y);
@@ -62896,7 +62949,7 @@ var EraserModel = class extends ElementModel {
62896
62949
  return point.transform(new this.scope.Matrix(this.pointsMatrix));
62897
62950
  }
62898
62951
  };
62899
- var import_lodash5 = __toESM2(require_lodash(), 1);
62952
+ var import_lodash6 = __toESM2(require_lodash(), 1);
62900
62953
  function _defineProperty14(e, r, t) {
62901
62954
  return (r = _toPropertyKey14(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e;
62902
62955
  }
@@ -63021,8 +63074,7 @@ var LaserPointerModel = class extends ElementModel {
63021
63074
  matrixedPoints() {
63022
63075
  const matrix = new this.scope.Matrix(this.pointsMatrix);
63023
63076
  const points = this.cachedPoints || this.points;
63024
- console.log("[][][] ,", this.points.length, this.cachedPoints?.length, this.localPoints.length);
63025
- const groupPoints = (0, import_lodash5.chunk)(points, 2).slice(this.sliceBegin);
63077
+ const groupPoints = (0, import_lodash6.chunk)(points, 2).slice(this.sliceBegin);
63026
63078
  return groupPoints.map((_ref) => {
63027
63079
  let [x, y] = _ref;
63028
63080
  return matrix.transform([x, y]);
@@ -63096,7 +63148,7 @@ var WhiteboardPermissions = class extends import_forge_room7.AbstractApplication
63096
63148
  return [WhiteboardPermissionFlag.draw, WhiteboardPermissionFlag.editSelf, WhiteboardPermissionFlag.editOthers, WhiteboardPermissionFlag.deleteSelf, WhiteboardPermissionFlag.deleteOthers, WhiteboardPermissionFlag.mainView, WhiteboardPermissionFlag.setOthersView].filter((v) => (v & value) !== 0);
63097
63149
  }
63098
63150
  };
63099
- var import_lodash6 = __toESM2(require_lodash(), 1);
63151
+ var import_lodash7 = __toESM2(require_lodash(), 1);
63100
63152
  function _defineProperty15(e, r, t) {
63101
63153
  return (r = _toPropertyKey15(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e;
63102
63154
  }
@@ -63155,7 +63207,7 @@ var StraightLineModel = class extends ElementModel {
63155
63207
  }
63156
63208
  renderLine() {
63157
63209
  const matrix = new this.scope.Matrix(this.pointsMatrix);
63158
- const papperPoints = (0, import_lodash6.chunk)(this.drawPoints, 2).map((item) => {
63210
+ const papperPoints = (0, import_lodash7.chunk)(this.drawPoints, 2).map((item) => {
63159
63211
  return new this.scope.Point(item[0], item[1]).transform(matrix);
63160
63212
  });
63161
63213
  const path = new this.scope.Path();
@@ -63283,6 +63335,7 @@ var ImageModel = class extends ElementModel {
63283
63335
  this.item = new this.scope.Raster(this.uuid);
63284
63336
  const matrix = new this.scope.Matrix(this.pointsMatrix);
63285
63337
  this.item.matrix = matrix;
63338
+ this.item.data.role = this.role;
63286
63339
  }
63287
63340
  onVectorUpdate() {
63288
63341
  const matrix = new this.scope.Matrix(this.pointsMatrix);
@@ -63311,8 +63364,12 @@ var ImageModel = class extends ElementModel {
63311
63364
  const cfg = new EditorConfig();
63312
63365
  cfg.resizeModel = () => "four-corner";
63313
63366
  cfg.uniformScale = () => true;
63367
+ cfg.translatable = () => !this.isBackground;
63314
63368
  return cfg;
63315
63369
  }
63370
+ mutationOrigin() {
63371
+ return this.isBackground ? backgroundElementsUndoOrigin : elementsUndoOrigin;
63372
+ }
63316
63373
  liveCursorPoint() {
63317
63374
  return null;
63318
63375
  }
@@ -63393,6 +63450,7 @@ var RenderableModel = class extends import_eventemitter3.default {
63393
63450
  flushRenderables() {
63394
63451
  this.emit("elementClear");
63395
63452
  const elements = Array.from(this.elements.values()).map((v) => this.convertToModel(v)).filter((v) => !!v);
63453
+ elements.sort((a2, b2) => this.compareElements(a2, b2));
63396
63454
  this.maxIndex = elements.reduce((r, n) => Math.max(r, n.index), -1);
63397
63455
  const clearIds = [];
63398
63456
  elements.forEach((model) => {
@@ -63454,7 +63512,32 @@ var RenderableModel = class extends import_eventemitter3.default {
63454
63512
  initElement(element) {
63455
63513
  element.shadowEmitter = this.shadowEmitter;
63456
63514
  }
63515
+ compareElementRole(roleA, roleB) {
63516
+ const a2 = roleA === "background" ? 0 : 1;
63517
+ const b2 = roleB === "background" ? 0 : 1;
63518
+ return a2 - b2;
63519
+ }
63520
+ compareElements(a2, b2) {
63521
+ const roleCompare = this.compareElementRole(a2.role, b2.role);
63522
+ if (roleCompare !== 0) {
63523
+ return roleCompare;
63524
+ }
63525
+ if (a2.index !== b2.index) {
63526
+ return a2.index - b2.index;
63527
+ }
63528
+ return a2.uuid.localeCompare(b2.uuid);
63529
+ }
63530
+ isBackgroundElement(uuid) {
63531
+ const element = this.elements.get(uuid);
63532
+ if (!element) {
63533
+ return false;
63534
+ }
63535
+ return (element.get("role") ?? "normal") === "background";
63536
+ }
63457
63537
  removeElementItem(uuid) {
63538
+ if (this.isBackgroundElement(uuid)) {
63539
+ return;
63540
+ }
63458
63541
  this.elements.delete(uuid);
63459
63542
  }
63460
63543
  confirmPermission() {
@@ -63465,15 +63548,21 @@ var RenderableModel = class extends import_eventemitter3.default {
63465
63548
  return hasPermission;
63466
63549
  }
63467
63550
  createImage(src) {
63551
+ let fit = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "legacy";
63552
+ let role = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "normal";
63468
63553
  if (!this.confirmPermission()) {
63469
63554
  return;
63470
63555
  }
63556
+ if (role === "background") {
63557
+ return this.upsertBackgroundImage(src, fit);
63558
+ }
63471
63559
  const yMap = new Y12.Map();
63472
63560
  this.elements.doc?.transact(() => {
63473
63561
  const uuid = this.uuid;
63474
63562
  yMap.set(ElementModel.KEYS.index, ++this.maxIndex);
63475
63563
  yMap.set(ElementModel.KEYS.uuid, uuid);
63476
63564
  yMap.set("type", "image");
63565
+ yMap.set("role", role);
63477
63566
  yMap.set(ElementModel.KEYS.ownerId, this.userManager.selfId);
63478
63567
  this.elements.set(uuid, yMap);
63479
63568
  }, elementsUndoOrigin);
@@ -63481,9 +63570,47 @@ var RenderableModel = class extends import_eventemitter3.default {
63481
63570
  model.bindObserver();
63482
63571
  model.root.set("src", src);
63483
63572
  model.ownerId = this.userManager.selfId;
63484
- this.fitImageToViewport(src, model);
63573
+ this.fitImageToViewport(src, model, fit);
63574
+ }
63575
+ upsertBackgroundImage(src, fit) {
63576
+ const backgroundEntries = Array.from(this.elements.entries()).filter((_ref) => {
63577
+ let [, elementMap] = _ref;
63578
+ return elementMap.get("type") === "image" && (elementMap.get("role") ?? "normal") === "background";
63579
+ });
63580
+ let targetMap = backgroundEntries[0]?.[1] ?? null;
63581
+ if (this.elements.doc) {
63582
+ this.elements.doc.transact(() => {
63583
+ backgroundEntries.slice(1).forEach((_ref2) => {
63584
+ let [key] = _ref2;
63585
+ return this.elements.delete(key);
63586
+ });
63587
+ if (!targetMap) {
63588
+ targetMap = new Y12.Map();
63589
+ const uuid = this.uuid;
63590
+ targetMap.set(ElementModel.KEYS.index, -1);
63591
+ targetMap.set(ElementModel.KEYS.uuid, uuid);
63592
+ targetMap.set("type", "image");
63593
+ targetMap.set("role", "background");
63594
+ targetMap.set(ElementModel.KEYS.ownerId, this.userManager.selfId);
63595
+ this.elements.set(uuid, targetMap);
63596
+ } else {
63597
+ targetMap.set("role", "background");
63598
+ targetMap.set(ElementModel.KEYS.ownerId, this.userManager.selfId);
63599
+ }
63600
+ }, backgroundElementsUndoOrigin);
63601
+ }
63602
+ if (!targetMap) {
63603
+ return;
63604
+ }
63605
+ const model = this.convertToModel(targetMap);
63606
+ if (!model || !(model instanceof ImageModel)) {
63607
+ return;
63608
+ }
63609
+ model.root.set("src", src);
63610
+ model.ownerId = this.userManager.selfId;
63611
+ this.fitImageToViewport(src, model, fit);
63485
63612
  }
63486
- fitImageToViewport(src, model) {
63613
+ fitImageToViewport(src, model, fit) {
63487
63614
  const center = this.scope.project.view.center;
63488
63615
  const fallbackMatrix = new this.scope.Matrix();
63489
63616
  fallbackMatrix.translate({
@@ -63500,9 +63627,9 @@ var RenderableModel = class extends import_eventemitter3.default {
63500
63627
  return;
63501
63628
  }
63502
63629
  const viewportBounds = this.scope.project.view.bounds;
63503
- const maxWidth = viewportBounds.width * 2 / 3;
63504
- const maxHeight = viewportBounds.height * 2 / 3;
63505
- const fitScale = Math.min(maxWidth / naturalWidth, maxHeight / naturalHeight, 1);
63630
+ const maxWidth = fit === "contain" ? viewportBounds.width : viewportBounds.width * 2 / 3;
63631
+ const maxHeight = fit === "contain" ? viewportBounds.height : viewportBounds.height * 2 / 3;
63632
+ const fitScale = fit === "contain" ? Math.min(maxWidth / naturalWidth, maxHeight / naturalHeight) : Math.min(maxWidth / naturalWidth, maxHeight / naturalHeight, 1);
63506
63633
  const nextMatrix = new this.scope.Matrix();
63507
63634
  nextMatrix.translate({
63508
63635
  x: center.x,
@@ -63525,7 +63652,7 @@ var RenderableModel = class extends import_eventemitter3.default {
63525
63652
  if (model.root.doc) {
63526
63653
  model.root.doc.transact(() => {
63527
63654
  model.root.set(ElementModel.KEYS.pointsMatrix, values);
63528
- }, elementsUndoOrigin);
63655
+ }, model.isBackground ? backgroundElementsUndoOrigin : elementsUndoOrigin);
63529
63656
  } else {
63530
63657
  model.root.set(ElementModel.KEYS.pointsMatrix, values);
63531
63658
  }
@@ -63785,7 +63912,7 @@ var RenderableModel = class extends import_eventemitter3.default {
63785
63912
  if (shadow) {
63786
63913
  yMap.set(ElementModel.KEYS.shadow, "layer");
63787
63914
  }
63788
- yMap.set(ElementModel.KEYS.points, new Y12.Array());
63915
+ yMap.set(ElementModel.KEYS.points, Y12.Array.from([x, y]));
63789
63916
  yMap.set(ElementModel.KEYS.strokeWidth, this.toolbarModel.strokeWidth);
63790
63917
  yMap.set(ElementModel.KEYS.strokeColor, this.toolbarModel.strokeColor);
63791
63918
  yMap.set(ElementModel.KEYS.fillColor, this.toolbarModel.fillColor);
@@ -63793,7 +63920,6 @@ var RenderableModel = class extends import_eventemitter3.default {
63793
63920
  this.elements.set(uuid, yMap);
63794
63921
  }, elementsUndoOrigin);
63795
63922
  pointTextModel.bindObserver();
63796
- pointTextModel.setPoints([x, y]);
63797
63923
  pointTextModel.fontSize = this.toolbarModel.fontSize;
63798
63924
  pointTextModel.fontFamily = this.toolbarModel.fontFamily;
63799
63925
  this.initElement(pointTextModel);
@@ -63825,7 +63951,7 @@ var RenderableModel = class extends import_eventemitter3.default {
63825
63951
  });
63826
63952
  }
63827
63953
  };
63828
- var import_lodash7 = __toESM2(require_lodash(), 1);
63954
+ var import_lodash8 = __toESM2(require_lodash(), 1);
63829
63955
  function Point(x, y) {
63830
63956
  this.X = x;
63831
63957
  this.Y = y;
@@ -64068,7 +64194,7 @@ var Recognizer = class {
64068
64194
  let maxX = -Number.MAX_VALUE;
64069
64195
  let minY = Number.MAX_VALUE;
64070
64196
  let maxY = -Number.MAX_VALUE;
64071
- const result = this.dollar.Recognize((0, import_lodash7.chunk)(points, 3).map((v) => {
64197
+ const result = this.dollar.Recognize((0, import_lodash8.chunk)(points, 2).map((v) => {
64072
64198
  minX = Math.min(minX, v[0]);
64073
64199
  maxX = Math.max(maxX, v[0]);
64074
64200
  minY = Math.min(minY, v[1]);
@@ -64116,22 +64242,33 @@ var CurveTool = class extends WhiteboardTool {
64116
64242
  _defineProperty19(this, "flushPendingPoints", () => {
64117
64243
  this.flushRafId = 0;
64118
64244
  if (this.elementModel && this.pendingPoints.length > 0) {
64119
- this.elementModel.appendPoints(this.pendingPoints);
64245
+ const appended = this.elementModel.appendPoints(this.pendingPoints);
64246
+ if (!appended) {
64247
+ this.resetStrokeState();
64248
+ return;
64249
+ }
64120
64250
  this.pendingPoints = [];
64121
64251
  }
64122
64252
  });
64123
64253
  }
64124
- onMouseDown(_event) {
64254
+ resetStrokeState() {
64125
64255
  this.pointCount = 0;
64126
64256
  this.pendingPoints = [];
64127
64257
  if (this.flushRafId) {
64128
64258
  cancelAnimationFrame(this.flushRafId);
64129
64259
  this.flushRafId = 0;
64130
64260
  }
64131
- if (this.elementModel) {
64132
- this.elementModel.dispose();
64133
- }
64134
64261
  this.elementModel = null;
64262
+ }
64263
+ cancelCurrentAction() {
64264
+ this.resetStrokeState();
64265
+ }
64266
+ onMouseDown(_event) {
64267
+ const previousElement = this.elementModel;
64268
+ this.resetStrokeState();
64269
+ if (previousElement) {
64270
+ previousElement.dispose();
64271
+ }
64135
64272
  this.modelGetter().then((model) => {
64136
64273
  if (model) {
64137
64274
  this.elementModel = model.createCurve(true);
@@ -64144,24 +64281,26 @@ var CurveTool = class extends WhiteboardTool {
64144
64281
  }
64145
64282
  const MIN_DISTANCE = 2;
64146
64283
  if (this.elementModel) {
64284
+ if (!this.elementModel.isAttached()) {
64285
+ this.resetStrokeState();
64286
+ return;
64287
+ }
64147
64288
  let lastX = 0;
64148
64289
  let lastY = 0;
64149
- if (this.pendingPoints.length >= 3) {
64150
- lastX = this.pendingPoints[this.pendingPoints.length - 3];
64151
- lastY = this.pendingPoints[this.pendingPoints.length - 2];
64290
+ if (this.pendingPoints.length >= 2) {
64291
+ lastX = this.pendingPoints[this.pendingPoints.length - 2];
64292
+ lastY = this.pendingPoints[this.pendingPoints.length - 1];
64152
64293
  } else {
64153
64294
  const len = this.elementModel.points.length;
64154
- if (len >= 3) {
64155
- lastX = this.elementModel.points[len - 3];
64156
- lastY = this.elementModel.points[len - 2];
64295
+ if (len >= 2) {
64296
+ lastX = this.elementModel.points[len - 2];
64297
+ lastY = this.elementModel.points[len - 1];
64157
64298
  }
64158
64299
  }
64159
64300
  const dist = Math.max(Math.abs(lastX - event.point.x), Math.abs(lastY - event.point.y));
64160
64301
  if (dist >= MIN_DISTANCE) {
64161
64302
  this.pointCount += 1;
64162
- const nativeEvent = event.event;
64163
- const pressure = nativeEvent.pointerType === "pen" && nativeEvent.pressure > 0 ? nativeEvent.pressure : 0;
64164
- this.pendingPoints.push(event.point.x, event.point.y, pressure);
64303
+ this.pendingPoints.push(event.point.x, event.point.y);
64165
64304
  if (!this.flushRafId) {
64166
64305
  this.flushRafId = requestAnimationFrame(this.flushPendingPoints);
64167
64306
  }
@@ -64174,22 +64313,27 @@ var CurveTool = class extends WhiteboardTool {
64174
64313
  this.flushRafId = 0;
64175
64314
  }
64176
64315
  this.flushPendingPoints();
64316
+ if (!this.elementModel || !this.elementModel.isAttached()) {
64317
+ this.resetStrokeState();
64318
+ return;
64319
+ }
64320
+ const currentElement = this.elementModel;
64321
+ const currentUuid = currentElement.uuid;
64322
+ const currentPointCount = this.pointCount;
64177
64323
  this.modelGetter().then((model) => {
64178
64324
  if (!model) {
64179
64325
  return;
64180
64326
  }
64181
- if (this.pointCount < 3 && this.elementModel) {
64182
- if (this.elementModel) {
64183
- model.removeElementItem(this.elementModel.uuid);
64184
- }
64327
+ if (currentPointCount < 3) {
64328
+ model.removeElementItem(currentUuid);
64185
64329
  }
64186
- if (this.elementModel) {
64187
- this.elementModel.shadow = "";
64330
+ if (currentElement.isAttached()) {
64331
+ currentElement.shadow = "";
64188
64332
  }
64189
- if (this.elementModel && event.event.metaKey) {
64190
- const result = this.recognizer.recognize(this.elementModel.points);
64333
+ if (currentElement.isAttached() && event.event.metaKey) {
64334
+ const result = this.recognizer.recognize(currentElement.points);
64191
64335
  if (result) {
64192
- model.removeElementItem(this.elementModel.uuid);
64336
+ model.removeElementItem(currentUuid);
64193
64337
  if (/^rectangle/.test(result.shape)) {
64194
64338
  const rect = model.createRectangle(false);
64195
64339
  rect?.setPoints([result.minX, result.minY, result.maxX, result.maxY]);
@@ -64208,6 +64352,9 @@ var CurveTool = class extends WhiteboardTool {
64208
64352
  }
64209
64353
  }
64210
64354
  }
64355
+ if (this.elementModel === currentElement) {
64356
+ this.resetStrokeState();
64357
+ }
64211
64358
  });
64212
64359
  }
64213
64360
  };
@@ -64397,6 +64544,9 @@ var SelectorTool = class extends WhiteboardTool {
64397
64544
  _defineProperty22(this, "showLiveCursor", false);
64398
64545
  this.selectElementsModel = selectElementsModel;
64399
64546
  }
64547
+ isSelectableItem(item) {
64548
+ return !!item.data.type && ["selector", "eraser", "laser"].indexOf(item.data.type) < 0 && item.data.role !== "background";
64549
+ }
64400
64550
  onMouseDown(event) {
64401
64551
  this.from = null;
64402
64552
  this.to = null;
@@ -64422,7 +64572,7 @@ var SelectorTool = class extends WhiteboardTool {
64422
64572
  this.elementModel.setPoints([rect.topLeft.x, rect.topLeft.y, rect.size.width, rect.size.height]);
64423
64573
  this.selectElementsModel.clearSelectElementForSelf();
64424
64574
  this.scope.project.activeLayer.children.forEach((item) => {
64425
- if (item.data.type && ["selector", "eraser", "laser"].indexOf(item.data.type) < 0) {
64575
+ if (this.isSelectableItem(item)) {
64426
64576
  if (rect.contains(item.bounds)) {
64427
64577
  this.selectElements.set(item.data.uuid, item.data.ownerId);
64428
64578
  } else {
@@ -64448,7 +64598,7 @@ var SelectorTool = class extends WhiteboardTool {
64448
64598
  return result;
64449
64599
  }, []);
64450
64600
  const hitResult = this.scope.project.hitTest(event.point);
64451
- if (hitResult && hitResult.item.data.uuid) {
64601
+ if (hitResult && hitResult.item.data.uuid && this.isSelectableItem(hitResult.item)) {
64452
64602
  elements.push({
64453
64603
  elementId: hitResult.item.data.uuid,
64454
64604
  ownerId: hitResult.item.data.ownerId
@@ -64975,7 +65125,7 @@ var Editor = class extends import_eventemitter34.default {
64975
65125
  };
64976
65126
  this.rootView.style.opacity = "0";
64977
65127
  }
64978
- if (target === this.frame) {
65128
+ if (target === this.frame && this.editorConfig?.translatable()) {
64979
65129
  evt.preventDefault();
64980
65130
  this.editMode = "translate";
64981
65131
  this.lastEditPoint = {
@@ -65280,7 +65430,6 @@ var Editor = class extends import_eventemitter34.default {
65280
65430
  this.shadowContainer.remove();
65281
65431
  this.shadowScope.project.activeLayer.addChild(this.shadowContainer);
65282
65432
  this.targets.forEach((model) => {
65283
- console.log("[][][] translateShadow model", model.root._dEH);
65284
65433
  model.shadow = this.shadowContainer.data.uuid;
65285
65434
  });
65286
65435
  }
@@ -66141,6 +66290,9 @@ var EraserTool = class extends WhiteboardTool {
66141
66290
  this.elementModel.appendPoints([event.point.x, event.point.y]);
66142
66291
  }
66143
66292
  this.scope.project.activeLayer.children.forEach((item) => {
66293
+ if (item.data.role === "background") {
66294
+ return;
66295
+ }
66144
66296
  if (item.data.type && ["selector", "eraser", "laser"].indexOf(item.data.type) < 0 && item.hitTest(event.point, {
66145
66297
  segments: true,
66146
66298
  stroke: true,
@@ -66151,6 +66303,9 @@ var EraserTool = class extends WhiteboardTool {
66151
66303
  }
66152
66304
  });
66153
66305
  this.shadowScope.project.activeLayer.children.forEach((item) => {
66306
+ if (item.data.role === "background") {
66307
+ return;
66308
+ }
66154
66309
  if (item.data.type && ["selector", "eraser", "laser"].indexOf(item.data.type) < 0 && item.hitTest(event.point, {
66155
66310
  segments: true,
66156
66311
  stroke: true,
@@ -66592,16 +66747,7 @@ var IndexedNavigation = class extends import_eventemitter311.default {
66592
66747
  return this.pageModel.pageList().filter((id) => /^_i_/.test(id));
66593
66748
  }
66594
66749
  get head() {
66595
- const headId = Object.keys(this.list).find((key) => {
66596
- return this.list[key] && this.list[key].prev === "";
66597
- });
66598
- if (!headId) {
66599
- (0, import_forge_room13.log)("indexed navigation confusion", {
66600
- list: JSON.stringify(this.list)
66601
- }, "error");
66602
- throw new Error("indexed navigation confusion");
66603
- }
66604
- return headId;
66750
+ return this.ensureValidList().head;
66605
66751
  }
66606
66752
  get lastNodeId() {
66607
66753
  let currentId = this.head;
@@ -66621,7 +66767,8 @@ var IndexedNavigation = class extends import_eventemitter311.default {
66621
66767
  _defineProperty36(this, "list", {});
66622
66768
  _defineProperty36(this, "hasPermission", void 0);
66623
66769
  _defineProperty36(this, "handleIndexedPageMapUpdate", (_evt) => {
66624
- this.list = this.indexedPageMap.get("list");
66770
+ this.list = this.normalizeList(this.indexedPageMap.get("list")) ?? {};
66771
+ this.ensureValidList("update");
66625
66772
  const needRemoveList = this.pageModel.pageList().filter((v) => /^_i_/.test(v) && Object.keys(this.list).indexOf(v) < 0);
66626
66773
  const needAddList = Object.keys(this.list).filter((v) => this.pageModel.pageList().indexOf(v) < 0);
66627
66774
  this.indexedPageMap.doc.transact(() => {
@@ -66654,11 +66801,156 @@ var IndexedNavigation = class extends import_eventemitter311.default {
66654
66801
  this.indexedPageMap.set("list", this.list);
66655
66802
  this.idPool.add("_i_");
66656
66803
  } else {
66657
- this.list = this.indexedPageMap.get("list");
66804
+ this.list = this.normalizeList(this.indexedPageMap.get("list")) ?? {};
66658
66805
  Object.keys(this.list).forEach((id) => this.idPool.add(id));
66806
+ this.ensureValidList("constructor");
66659
66807
  }
66660
66808
  this.indexedPageMap.observe(this.handleIndexedPageMapUpdate);
66661
66809
  }
66810
+ normalizeList(list) {
66811
+ if (!list || typeof list !== "object" || Array.isArray(list)) {
66812
+ return null;
66813
+ }
66814
+ const nextList = {};
66815
+ for (const [id, node] of Object.entries(list)) {
66816
+ if (!/^_i_/.test(id) || !node || typeof node !== "object") {
66817
+ return null;
66818
+ }
66819
+ const {
66820
+ prev,
66821
+ next
66822
+ } = node;
66823
+ if (typeof prev !== "string" || typeof next !== "string") {
66824
+ return null;
66825
+ }
66826
+ nextList[id] = {
66827
+ prev,
66828
+ next
66829
+ };
66830
+ }
66831
+ return nextList;
66832
+ }
66833
+ validateList(list) {
66834
+ const ids = Object.keys(list);
66835
+ if (ids.length === 0) {
66836
+ return {
66837
+ valid: false,
66838
+ reason: "empty list"
66839
+ };
66840
+ }
66841
+ const heads = ids.filter((id) => list[id].prev === "");
66842
+ if (heads.length !== 1) {
66843
+ return {
66844
+ valid: false,
66845
+ reason: `expected one head, got ${heads.length}`
66846
+ };
66847
+ }
66848
+ for (const id of ids) {
66849
+ const node = list[id];
66850
+ if (node.prev && !list[node.prev]) {
66851
+ return {
66852
+ valid: false,
66853
+ reason: `missing prev node ${node.prev}`
66854
+ };
66855
+ }
66856
+ if (node.next && !list[node.next]) {
66857
+ return {
66858
+ valid: false,
66859
+ reason: `missing next node ${node.next}`
66860
+ };
66861
+ }
66862
+ if (node.prev && list[node.prev].next !== id) {
66863
+ return {
66864
+ valid: false,
66865
+ reason: `prev link mismatch for ${id}`
66866
+ };
66867
+ }
66868
+ if (node.next && list[node.next].prev !== id) {
66869
+ return {
66870
+ valid: false,
66871
+ reason: `next link mismatch for ${id}`
66872
+ };
66873
+ }
66874
+ }
66875
+ const visited = /* @__PURE__ */ new Set();
66876
+ let currentId = heads[0];
66877
+ while (currentId) {
66878
+ if (visited.has(currentId)) {
66879
+ return {
66880
+ valid: false,
66881
+ reason: `cycle at ${currentId}`
66882
+ };
66883
+ }
66884
+ visited.add(currentId);
66885
+ currentId = list[currentId].next;
66886
+ }
66887
+ if (visited.size !== ids.length) {
66888
+ return {
66889
+ valid: false,
66890
+ reason: "detached nodes"
66891
+ };
66892
+ }
66893
+ return {
66894
+ valid: true,
66895
+ head: heads[0]
66896
+ };
66897
+ }
66898
+ createList(ids) {
66899
+ return ids.reduce((list, id, index) => {
66900
+ list[id] = {
66901
+ prev: ids[index - 1] ?? "",
66902
+ next: ids[index + 1] ?? ""
66903
+ };
66904
+ return list;
66905
+ }, {});
66906
+ }
66907
+ repairList(reason) {
66908
+ const pageIds = this.idList;
66909
+ const ids = pageIds.length > 0 ? pageIds : Object.keys(this.list).filter((id) => /^_i_/.test(id));
66910
+ const nextIds = ids.length > 0 ? ids : ["_i_"];
66911
+ const nextList = this.createList(nextIds);
66912
+ (0, import_forge_room13.log)("indexed navigation recovered", {
66913
+ reason,
66914
+ pageList: JSON.stringify(this.pageModel.pageList()),
66915
+ list: JSON.stringify(this.list),
66916
+ nextList: JSON.stringify(nextList)
66917
+ }, "warn");
66918
+ const apply = () => {
66919
+ for (const id of nextIds) {
66920
+ if (this.pageModel.pageList().indexOf(id) < 0) {
66921
+ this.pageModel.addPage(id);
66922
+ }
66923
+ }
66924
+ this.list = nextList;
66925
+ this.indexedPageMap.set("list", nextList);
66926
+ };
66927
+ if (this.indexedPageMap.doc) {
66928
+ this.indexedPageMap.doc.transact(apply);
66929
+ } else {
66930
+ apply();
66931
+ }
66932
+ nextIds.forEach((id) => this.idPool.add(id));
66933
+ return nextIds[0];
66934
+ }
66935
+ ensureValidList() {
66936
+ let context = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "read";
66937
+ const normalized = this.normalizeList(this.list);
66938
+ if (!normalized) {
66939
+ return {
66940
+ head: this.repairList(`${context}: invalid list`)
66941
+ };
66942
+ }
66943
+ this.list = normalized;
66944
+ const validation = this.validateList(this.list);
66945
+ if (!validation.valid) {
66946
+ return {
66947
+ head: this.repairList(`${context}: ${validation.reason}`)
66948
+ };
66949
+ }
66950
+ return {
66951
+ head: validation.head
66952
+ };
66953
+ }
66662
66954
  getNextId() {
66663
66955
  const cache = Array.from(this.idPool).filter((id) => this.idList.indexOf(id) < 0);
66664
66956
  if (cache.length > 0) {
@@ -67590,7 +67882,6 @@ var WhiteboardApplication = class _WhiteboardApplication extends import_forge_ro
67590
67882
  this.emitter.emit("elementDeselected", userId);
67591
67883
  return;
67592
67884
  }
67593
- editor.show();
67594
67885
  const targetLayerId = this.userMap(userId).get(WhiteboardKeys.currentPage);
67595
67886
  const selfLayerId = this.userMap(this.userId).get(WhiteboardKeys.currentPage);
67596
67887
  if (targetLayerId !== selfLayerId || !this.layers.has(targetLayerId)) {
@@ -67598,7 +67889,13 @@ var WhiteboardApplication = class _WhiteboardApplication extends import_forge_ro
67598
67889
  }
67599
67890
  const elementModels = elements.map((id) => {
67600
67891
  return this.layers.get(targetLayerId).elementModels.get(id);
67601
- }).filter((v) => !!v);
67892
+ }).filter((model) => !!model && !model.isBackground);
67893
+ if (elementModels.length === 0) {
67894
+ editor.hidden();
67895
+ this.emitter.emit("elementDeselected", userId);
67896
+ return;
67897
+ }
67898
+ editor.show();
67602
67899
  editor.setTargets(elementModels);
67603
67900
  if (elementModels.length === 1) {
67604
67901
  const model = elementModels[0];
@@ -67790,14 +68087,17 @@ var WhiteboardApplication = class _WhiteboardApplication extends import_forge_ro
67790
68087
  this.camera.resetViewMatrixToMain();
67791
68088
  }
67792
68089
  };
67793
- this.emitter.insertImage = (src, pageId) => {
68090
+ this.emitter.insertImage = (src, options) => {
67794
68091
  if (!/https/.test(src)) {
67795
68092
  (0, import_forge_room.log)("[@netless/forge-whiteboard] invalid image url, src needs to be in the HTTPS protocol.", {
67796
68093
  src
67797
68094
  }, "warn");
67798
68095
  return;
67799
68096
  }
67800
- let targetPageId = pageId;
68097
+ const normalizedOptions = typeof options === "string" ? {
68098
+ pageId: options
68099
+ } : options ?? {};
68100
+ let targetPageId = normalizedOptions.pageId;
67801
68101
  if (!targetPageId) {
67802
68102
  targetPageId = this.pageModel.getCurrentPage(this.userManager.selfId);
67803
68103
  }
@@ -67805,13 +68105,16 @@ var WhiteboardApplication = class _WhiteboardApplication extends import_forge_ro
67805
68105
  (0, import_forge_room.log)("[@netless/forge-whiteboard] page not found", {}, "warn");
67806
68106
  return;
67807
68107
  }
67808
- this.layers.get(targetPageId)?.createImage(src);
68108
+ this.layers.get(targetPageId)?.createImage(src, normalizedOptions.fit ?? "legacy", normalizedOptions.role ?? "normal");
67809
68109
  };
67810
68110
  this.emitter.removeElement = (pageId, elementId) => {
67811
68111
  if (!this.layers.has(pageId)) {
67812
68112
  (0, import_forge_room.log)("[@netless/forge-whiteboard] page not found", {}, "warn");
67813
68113
  return;
67814
68114
  }
68115
+ if (this.layers.get(pageId)?.isBackgroundElement(elementId)) {
68116
+ return;
68117
+ }
67815
68118
  this.layers.get(pageId)?.removeElementItem(elementId);
67816
68119
  };
67817
68120
  this.emitter.getViewModel = (userId) => {
@@ -67862,7 +68165,11 @@ var WhiteboardApplication = class _WhiteboardApplication extends import_forge_ro
67862
68165
  if (model) {
67863
68166
  if (model.elements.doc) {
67864
68167
  model.elements.doc.transact(() => {
67865
- model.elements.clear();
68168
+ for (const key of Array.from(model.elements.keys())) {
68169
+ if (!model.isBackgroundElement(key)) {
68170
+ model.elements.delete(key);
68171
+ }
68172
+ }
67866
68173
  }, elementsUndoOrigin);
67867
68174
  } else {
67868
68175
  model.elementModels.clear();
@@ -68274,7 +68581,9 @@ var WhiteboardApplication = class _WhiteboardApplication extends import_forge_ro
68274
68581
  const at = this.findElementIndex(element.data.index, parent);
68275
68582
  for (let i = at; i >= 0; i--) {
68276
68583
  const child = children[i - 1];
68277
- if (!child || child.data.index < element.data.index || child.data.uuid < element.data.uuid) {
68584
+ const childRole = child?.data.role === "background" ? 0 : 1;
68585
+ const elementRole = element.data.role === "background" ? 0 : 1;
68586
+ if (!child || childRole < elementRole || childRole === elementRole && child.data.index < element.data.index || childRole === elementRole && child.data.index === element.data.index && child.data.uuid < element.data.uuid) {
68278
68587
  parent.insertChild(i, element);
68279
68588
  break;
68280
68589
  }