@trebco/treb 28.15.1 → 28.17.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -38,6 +38,12 @@
38
38
 
39
39
  // --- toolbar ---------------------------------------------------------------
40
40
 
41
+ /* source: bootstrap-icons-1.8.3/text-indent-left.svg */
42
+ --icon-text-indent: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-text-indent-left" viewBox="0 0 16 16"><path d="M2 3.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5m.646 2.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L4.293 8 2.646 6.354a.5.5 0 0 1 0-.708M7 6.5a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5m0 3a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5m-5 3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5"/></svg>');
43
+
44
+ /* source: bootstrap-icons-1.8.3/text-indent-right.svg */
45
+ --icon-text-outdent: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-text-indent-right" viewBox="0 0 16 16"><path d="M2 3.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5m10.646 2.146a.5.5 0 0 1 .708.708L11.707 8l1.647 1.646a.5.5 0 0 1-.708.708l-2-2a.5.5 0 0 1 0-.708zM2 6.5a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5m0 3a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5m0 3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5"/></svg>');
46
+
41
47
  /* source: bootstrap-icons-1.8.3/text-left.svg */
42
48
  --icon-text-align-left: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' viewBox='0 0 16 16'> <path fill-rule='evenodd' d='M2 12.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z'/> </svg>");
43
49
 
@@ -23,7 +23,8 @@ import type { ICellAddress,
23
23
  PreparedText, RenderTextPart,
24
24
  Cell, Size,
25
25
  CellStyle,
26
- Theme} from 'treb-base-types';
26
+ Theme,
27
+ HorizontalAlign} from 'treb-base-types';
27
28
  import { TextPartFlag, Style, ValueType, Area, Rectangle, ThemeColor, ThemeColor2 } from 'treb-base-types';
28
29
 
29
30
  import type { Tile } from '../types/tile';
@@ -146,12 +147,22 @@ export class TileRenderer {
146
147
  // flush all, mark dirty and drop areas.
147
148
 
148
149
  const cells = this.view.active_sheet.cells;
150
+
151
+ for (const cell of cells.Iterate()) {
152
+ if (cell.renderer_data?.overflowed) {
153
+ cell.renderer_data = undefined;
154
+ cell.render_clean[this.view.view_index] = false;
155
+ }
156
+ }
157
+
158
+ /*
149
159
  cells.IterateAll(cell => {
150
160
  if (cell.renderer_data?.overflowed) {
151
161
  cell.renderer_data = undefined;
152
162
  cell.render_clean[this.view.view_index] = false;
153
163
  }
154
164
  });
165
+ */
155
166
 
156
167
  for (const overflow_area of this.overflow_areas) {
157
168
  overflow_area.tile.dirty = true;
@@ -727,10 +738,22 @@ export class TileRenderer {
727
738
  // precalculate indent as string so we can use layout
728
739
 
729
740
  let indent = '';
741
+ let align: HorizontalAlign|undefined;
742
+
730
743
  if (style.indent) {
744
+
731
745
  for (let i = 0; i < style.indent; i++) {
732
746
  indent += DEFAULT_INDENT;
733
747
  }
748
+
749
+ align = style.horizontal_align;
750
+
751
+ // default might be left or right based on type
752
+
753
+ if (!align) {
754
+ align = (cell.type === ValueType.number || cell.calculated_type === ValueType.number) ? 'right' : 'left';
755
+ }
756
+
734
757
  }
735
758
 
736
759
  if (Array.isArray(formatted)) {
@@ -744,10 +767,11 @@ export class TileRenderer {
744
767
  // this is a single line, with number formatting
745
768
 
746
769
  if (indent) {
747
- if (style.horizontal_align === 'right') {
770
+
771
+ if (align === 'right') {
748
772
  formatted.push({ text: indent });
749
773
  }
750
- else if (style.horizontal_align !== 'center') {
774
+ else if (align === 'left') {
751
775
  formatted.unshift({ text: indent });
752
776
  }
753
777
  }
@@ -953,13 +977,12 @@ export class TileRenderer {
953
977
  });
954
978
 
955
979
  if (style.indent) {
956
- if (style.horizontal_align === 'right') {
980
+ if (align === 'right') {
957
981
  line_string.push({ text: indent, hidden: false, width: indent_width });
958
982
  }
959
- else if (style.horizontal_align !== 'center') {
983
+ else if (align === 'left') {
960
984
  line_string.unshift({ text: indent, hidden: false, width: indent_width });
961
985
  }
962
-
963
986
  }
964
987
 
965
988
  strings.push(line_string);
@@ -978,13 +1001,12 @@ export class TileRenderer {
978
1001
  const parts: RenderTextPart[] = [];
979
1002
 
980
1003
  if (style.indent) {
981
- if (style.horizontal_align === 'right') {
1004
+ if (align === 'right') {
982
1005
  line.push({ text: indent });
983
1006
  }
984
- else if (style.horizontal_align !== 'center') {
1007
+ else if (align === 'left') {
985
1008
  line.unshift({ text: indent });
986
1009
  }
987
-
988
1010
  }
989
1011
 
990
1012
  let line_width = 0;
@@ -2044,6 +2044,21 @@ export class Grid extends GridBase {
2044
2044
  }
2045
2045
  */
2046
2046
 
2047
+ public Indent(area?: Area, delta = 0): void {
2048
+
2049
+ if (!area) {
2050
+ if (this.primary_selection.empty) { return; }
2051
+ area = this.primary_selection.area;
2052
+ }
2053
+
2054
+ this.ExecCommand({
2055
+ key: CommandKey.Indent,
2056
+ area,
2057
+ delta,
2058
+ });
2059
+
2060
+ }
2061
+
2047
2062
  /** updated API method, probably change the name */
2048
2063
  public ApplyBorders2(area?: Area, borders: BorderConstants = BorderConstants.None, color?: Color, width = 1): void {
2049
2064
 
@@ -4972,6 +4987,15 @@ export class Grid extends GridBase {
4972
4987
  }
4973
4988
  }
4974
4989
  else if (array) {
4990
+
4991
+ for (const cell of this.active_sheet.cells.Iterate(selection.area, false)) {
4992
+ if (cell.area) {
4993
+ this.Error(ErrorCode.array);
4994
+ return;
4995
+ }
4996
+ }
4997
+
4998
+ /*
4975
4999
  let existing_array = false;
4976
5000
  this.active_sheet.cells.Apply(selection.area, (element: Cell) => {
4977
5001
  if (element.area) {
@@ -4982,6 +5006,8 @@ export class Grid extends GridBase {
4982
5006
  this.Error(ErrorCode.array);
4983
5007
  return;
4984
5008
  }
5009
+ */
5010
+
4985
5011
  }
4986
5012
 
4987
5013
  if (cell.validation && cell.validation.error) {
@@ -6099,9 +6125,28 @@ export class Grid extends GridBase {
6099
6125
  let real_area = this.active_sheet.RealArea(area);
6100
6126
  if (!target) target = real_area.start;
6101
6127
 
6102
- let recheck = true;
6128
+ // there has to be a better way to do this...
6129
+
6130
+ // the operation here is composing the selection by adding all merge
6131
+ // areas. the issue is that when you do that, you might be adding other
6132
+ // cells that are not in the merge area (because the selection has to
6133
+ // be a rectangle) and one of those new cells might itself be merged.
6134
+ // so we need to iterate. there's a lot of duplication here, though.
6135
+
6136
+ recheck_loop: while (true) {
6137
+ for (const cell of this.active_sheet.cells.Iterate(real_area, false)) {
6138
+ if (cell.merge_area && !real_area.ContainsArea(cell.merge_area)) {
6139
+ area.ConsumeArea(cell.merge_area);
6140
+ real_area = this.active_sheet.RealArea(area);
6141
+ continue recheck_loop;
6142
+ }
6143
+ }
6144
+ break;
6145
+ }
6103
6146
 
6104
- // there has to be a better way to do this...
6147
+ /*
6148
+
6149
+ let recheck = true;
6105
6150
 
6106
6151
  while (recheck) {
6107
6152
  recheck = false;
@@ -6113,6 +6158,7 @@ export class Grid extends GridBase {
6113
6158
  }
6114
6159
  });
6115
6160
  }
6161
+ */
6116
6162
 
6117
6163
  selection.area = new Area({ ...area.start, sheet_id: this.active_sheet.id }, area.end);
6118
6164
  if (target) {
@@ -841,33 +841,49 @@ export class GridBase {
841
841
 
842
842
  let valid = true;
843
843
 
844
- sheet.cells.Apply2(area, cell => {
844
+ for (const cell of sheet.cells.Iterate(area)) {
845
+
845
846
  if (cell.style?.locked) {
846
847
  console.info('invalid: locked cells');
847
- valid = false;
848
+ return false;
848
849
  }
849
850
  if (cell.merge_area) {
850
851
  if (!area.Contains(cell.merge_area.start) || !area.Contains(cell.merge_area.end)) {
851
852
  console.info('invalid: merge area');
852
- valid = false;
853
+ return false;
853
854
  }
854
855
  }
855
856
  if (cell.area) {
856
857
  if (!area.Contains(cell.area.start) || !area.Contains(cell.area.end)) {
857
858
  console.info('invalid: array');
859
+ return false;
860
+ }
861
+ }
862
+
863
+ }
864
+
865
+ /*
866
+ sheet.cells.Apply2(area, cell => {
867
+ if (cell.style?.locked) {
868
+ console.info('invalid: locked cells');
869
+ valid = false;
870
+ }
871
+ if (cell.merge_area) {
872
+ if (!area.Contains(cell.merge_area.start) || !area.Contains(cell.merge_area.end)) {
873
+ console.info('invalid: merge area');
858
874
  valid = false;
859
875
  }
860
876
  }
861
- /* ok for paste
862
- if (cell.table) {
863
- if (!area.Contains(cell.table.area.start) || !area.Contains(cell.table.area.end)) {
864
- console.info('invalid: table');
877
+ if (cell.area) {
878
+ if (!area.Contains(cell.area.start) || !area.Contains(cell.area.end)) {
879
+ console.info('invalid: array');
865
880
  valid = false;
866
881
  }
867
882
  }
868
- */
883
+
869
884
  return valid;
870
885
  });
886
+ */
871
887
 
872
888
  if (!valid) {
873
889
  return false;
@@ -1406,6 +1422,46 @@ export class GridBase {
1406
1422
  // duh, no we don't. if the cell is in the table it will have
1407
1423
  // a reference.
1408
1424
 
1425
+ for (const cell of sheet.cells.Iterate()) {
1426
+
1427
+ if (cell.ValueIsFormula()) {
1428
+ let updated_formula = false;
1429
+ const parse_result = this.parser.Parse(cell.value);
1430
+ if (parse_result.expression) {
1431
+
1432
+ this.parser.Walk(parse_result.expression, (unit) => {
1433
+ if (unit.type === 'structured-reference') {
1434
+
1435
+ if (unit.table.toLowerCase() === table_name ||
1436
+ (!unit.table && cell.table === table)) {
1437
+
1438
+ // we may need to rewrite...
1439
+ for (const [key, value] of update.entries()) {
1440
+ if (unit.column.toLowerCase() === key) {
1441
+
1442
+ // ok we need to update
1443
+ unit.column = value;
1444
+ updated_formula = true;
1445
+
1446
+ }
1447
+ }
1448
+
1449
+ }
1450
+ }
1451
+ return true;
1452
+ });
1453
+ if (updated_formula) {
1454
+ console.info('updating value');
1455
+ cell.value = '=' + this.parser.Render(parse_result.expression, {
1456
+ missing: '',
1457
+ });
1458
+ }
1459
+ }
1460
+ }
1461
+
1462
+ }
1463
+
1464
+ /*
1409
1465
  sheet.cells.IterateAll(cell => {
1410
1466
  if (cell.ValueIsFormula()) {
1411
1467
  let updated_formula = false;
@@ -1442,6 +1498,7 @@ export class GridBase {
1442
1498
  }
1443
1499
  }
1444
1500
  });
1501
+ */
1445
1502
 
1446
1503
  }
1447
1504
  }
@@ -1843,6 +1900,7 @@ export class GridBase {
1843
1900
  case CommandKey.Clear:
1844
1901
  case CommandKey.SetNote:
1845
1902
  case CommandKey.SetLink:
1903
+ case CommandKey.Indent:
1846
1904
  case CommandKey.UpdateBorders:
1847
1905
  case CommandKey.MergeCells:
1848
1906
  case CommandKey.UnmergeCells:
@@ -2135,6 +2193,17 @@ export class GridBase {
2135
2193
  for (const sheet of sheets) {
2136
2194
 
2137
2195
  // cells
2196
+ for (const cell of sheet.cells.Iterate()) {
2197
+ if (cell.ValueIsFormula()) {
2198
+ const updated = this.PatchExpressionSheetName(cell.value||'', old_name, name);
2199
+ if (updated) {
2200
+ cell.value = updated;
2201
+ changes++;
2202
+ }
2203
+ }
2204
+ }
2205
+
2206
+ /*
2138
2207
  sheet.cells.IterateAll((cell: Cell) => {
2139
2208
  if (cell.ValueIsFormula()) {
2140
2209
  const updated = this.PatchExpressionSheetName(cell.value||'', old_name, name);
@@ -2144,6 +2213,7 @@ export class GridBase {
2144
2213
  }
2145
2214
  }
2146
2215
  });
2216
+ */
2147
2217
 
2148
2218
  // conditionals
2149
2219
  if (sheet.conditional_formats?.length) {
@@ -2448,12 +2518,21 @@ export class GridBase {
2448
2518
  let error = false;
2449
2519
  area = sheet.RealArea(area); // collapse
2450
2520
 
2521
+ for (const cell of sheet.cells.Iterate(area)) {
2522
+ if (cell.area && !area.ContainsArea(cell.area)) {
2523
+ this.Error(ErrorCode.array);
2524
+ return;
2525
+ }
2526
+ }
2527
+
2528
+ /*
2451
2529
  sheet.cells.Apply(area, (cell) => {
2452
2530
  if (cell.area && !area.ContainsArea(cell.area)) {
2453
2531
  // throw new Error('can\'t change part of an array');
2454
2532
  error = true;
2455
2533
  }
2456
2534
  });
2535
+ */
2457
2536
 
2458
2537
  // if the area completely encloses a table, delete the table
2459
2538
  const table_keys = this.model.tables.keys();
@@ -2870,6 +2949,18 @@ export class GridBase {
2870
2949
  for (const sheet of this.model.sheets.list) {
2871
2950
  const is_target = sheet === target_sheet;
2872
2951
 
2952
+ for (const cell of sheet.cells.Iterate()) {
2953
+ if (cell.ValueIsFormula()) {
2954
+ const modified = this.PatchFormulasInternal(cell.value || '',
2955
+ command.before_row, command.count, 0, 0,
2956
+ target_sheet_name, is_target);
2957
+ if (modified) {
2958
+ cell.value = modified;
2959
+ }
2960
+ }
2961
+ }
2962
+
2963
+ /*
2873
2964
  sheet.cells.IterateAll((cell: Cell) => {
2874
2965
  if (cell.ValueIsFormula()) {
2875
2966
  const modified = this.PatchFormulasInternal(cell.value || '',
@@ -2880,6 +2971,7 @@ export class GridBase {
2880
2971
  }
2881
2972
  }
2882
2973
  });
2974
+ */
2883
2975
 
2884
2976
  for (const annotation of sheet.annotations) {
2885
2977
  if (annotation.data.formula) {
@@ -3216,6 +3308,18 @@ export class GridBase {
3216
3308
  for (const sheet of this.model.sheets.list) {
3217
3309
  const is_target = sheet === target_sheet;
3218
3310
 
3311
+ for (const cell of sheet.cells.Iterate()) {
3312
+ if (cell.ValueIsFormula()) {
3313
+ const modified = this.PatchFormulasInternal(cell.value || '', 0, 0,
3314
+ command.before_column, command.count,
3315
+ target_sheet_name, is_target);
3316
+ if (modified) {
3317
+ cell.value = modified;
3318
+ }
3319
+ }
3320
+ }
3321
+
3322
+ /*
3219
3323
  sheet.cells.IterateAll((cell: Cell) => {
3220
3324
  if (cell.ValueIsFormula()) {
3221
3325
  const modified = this.PatchFormulasInternal(cell.value || '', 0, 0,
@@ -3226,6 +3330,7 @@ export class GridBase {
3226
3330
  }
3227
3331
  }
3228
3332
  });
3333
+ */
3229
3334
 
3230
3335
  for (const annotation of sheet.annotations) {
3231
3336
  if (annotation.data.formula) {
@@ -3760,6 +3865,15 @@ export class GridBase {
3760
3865
  const list: Record<string, Area> = {};
3761
3866
  const area = new Area(command.area.start, command.area.end);
3762
3867
 
3868
+ for (const cell of sheet.cells.Iterate(area, false)) {
3869
+ if (cell.merge_area) {
3870
+ const label = Area.CellAddressToLabel(cell.merge_area.start) + ':'
3871
+ + Area.CellAddressToLabel(cell.merge_area.end);
3872
+ list[label] = cell.merge_area;
3873
+ }
3874
+ }
3875
+
3876
+ /*
3763
3877
  sheet.cells.Apply(area, (cell: Cell) => {
3764
3878
  if (cell.merge_area) {
3765
3879
  const label = Area.CellAddressToLabel(cell.merge_area.start) + ':'
@@ -3767,6 +3881,7 @@ export class GridBase {
3767
3881
  list[label] = cell.merge_area;
3768
3882
  }
3769
3883
  }, false);
3884
+ */
3770
3885
 
3771
3886
  const keys = Object.keys(list);
3772
3887
 
@@ -3795,6 +3910,39 @@ export class GridBase {
3795
3910
  }
3796
3911
  break;
3797
3912
 
3913
+ case CommandKey.Indent:
3914
+ {
3915
+ let area: Area|undefined;
3916
+ const sheet = this.FindSheet(command.area);
3917
+
3918
+ if (IsCellAddress(command.area)) {
3919
+ area = new Area(command.area);
3920
+ const style = sheet.GetCellStyle(command.area, true);
3921
+ sheet.UpdateCellStyle(command.area, {
3922
+ indent: Math.max(0, (style.indent || 0) + command.delta),
3923
+ }, true);
3924
+ }
3925
+ else {
3926
+ area = new Area(command.area.start, command.area.end);
3927
+ for (const address of area) {
3928
+ const style = sheet.GetCellStyle(address, true);
3929
+ sheet.UpdateCellStyle(address, {
3930
+ indent: Math.max(0, (style.indent || 0) + command.delta),
3931
+ }, true);
3932
+ };
3933
+ }
3934
+
3935
+ if (sheet === this.active_sheet) {
3936
+ flags.style_area = Area.Join(area, flags.style_area);
3937
+ flags.render_area = Area.Join(area, flags.render_area);
3938
+ }
3939
+ else {
3940
+ flags.style_event = true;
3941
+ }
3942
+
3943
+ }
3944
+ break;
3945
+
3798
3946
  case CommandKey.UpdateStyle:
3799
3947
  {
3800
3948
  // COEDITING: handles sheet ID properly
@@ -52,6 +52,7 @@ export enum CommandKey {
52
52
  SetRange,
53
53
  UpdateStyle,
54
54
  UpdateBorders,
55
+ Indent,
55
56
  MergeCells,
56
57
  UnmergeCells,
57
58
  Clear,
@@ -278,6 +279,12 @@ export interface UpdateBordersCommand {
278
279
  width?: number;
279
280
  }
280
281
 
282
+ export interface IndentCommand {
283
+ key: CommandKey.Indent,
284
+ area: IArea,
285
+ delta: number,
286
+ }
287
+
281
288
  /** update style in area. area can be cell(s), sheet, row(s), column(s) */
282
289
  export interface UpdateStyleCommand {
283
290
  key: CommandKey.UpdateStyle;
@@ -465,6 +472,7 @@ export type Command =
465
472
  | ResetCommand
466
473
  | SelectCommand
467
474
  | FreezeCommand
475
+ | IndentCommand
468
476
  | SetNoteCommand
469
477
  | SetLinkCommand
470
478
  | SetNameCommand