@trebco/treb 29.3.3 → 29.4.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.
@@ -21,9 +21,6 @@
21
21
 
22
22
  // --- imports -----------------------------------------------------------------
23
23
 
24
- // eslint-disable-next-line @typescript-eslint/triple-slash-reference
25
- /// <reference path="./content-types.d.ts" />
26
-
27
24
  import type {
28
25
  GridEvent,
29
26
  SheetChangeEvent, GridOptions,
@@ -103,6 +100,11 @@ import type { StateLeafVertex } from 'treb-calculator';
103
100
 
104
101
  // --- worker ------------------------------------------------------------------
105
102
 
103
+ /**
104
+ * import type for our worker, plus markup files
105
+ */
106
+ import './content-types.d.ts';
107
+
106
108
  /**
107
109
  * import the worker as a script file. tsc will read this on typecheck but
108
110
  * that's actually to the good; when we build with esbuild we will inline
@@ -3005,7 +3007,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
3005
3007
 
3006
3008
  this.grid.Reset();
3007
3009
  this.ResetInternal();
3008
- this.calculator.AttachModel();
3010
+ // this.calculator.AttachModel();
3009
3011
  this.UpdateAC();
3010
3012
 
3011
3013
  this.Publish({ type: 'reset' });
@@ -3491,25 +3493,30 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
3491
3493
  /**
3492
3494
  * set or clear cell valiation.
3493
3495
  *
3494
- * @param address - target cell
3496
+ * @param target - target cell/area
3495
3497
  * @param validation - a spreadsheet range, list of data, or undefined. pass
3496
3498
  * undefined to remove existing cell validation.
3497
3499
  * @param error - setting an invalid value in the target cell is an error (and
3498
3500
  * is blocked). defaults to false.
3499
3501
  */
3500
- public SetValidation(address: AddressReference, validation?: RangeReference|CellValue[], error?: boolean) {
3502
+ public SetValidation(target: RangeReference, validation?: RangeReference|CellValue[], error?: boolean) {
3501
3503
 
3502
- if (typeof address === 'string') {
3503
- const reference = this.model.ResolveAddress(address, this.grid.active_sheet);
3504
- address = IsCellAddress(reference) ? reference : reference.start;
3504
+ if (typeof target === 'string') {
3505
+ const reference = this.model.ResolveAddress(target, this.grid.active_sheet);
3506
+ target = IsArea(reference) ? new Area(reference.start, reference.end) : new Area(reference);
3507
+ // address = IsCellAddress(reference) ? reference : reference.start;
3508
+ }
3509
+
3510
+ if (IsCellAddress(target)) {
3511
+ target = new Area(target);
3505
3512
  }
3506
3513
 
3507
3514
  if (typeof validation === 'undefined' || Array.isArray(validation)) {
3508
- this.grid.SetValidation(address, validation, error);
3515
+ this.grid.SetValidation(target, validation, error);
3509
3516
  }
3510
3517
  else {
3511
3518
  const range = this.model.ResolveArea(validation, this.grid.active_sheet);
3512
- this.grid.SetValidation(address, range, error);
3519
+ this.grid.SetValidation(target, range, error);
3513
3520
  }
3514
3521
 
3515
3522
  }
@@ -4626,7 +4633,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
4626
4633
 
4627
4634
  // this one _is_ the grid cells
4628
4635
 
4629
- this.calculator.AttachModel();
4636
+ // this.calculator.AttachModel();
4630
4637
  this.Publish({ type: 'load', source, });
4631
4638
  this.UpdateDocumentStyles();
4632
4639
 
@@ -5845,9 +5852,8 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
5845
5852
 
5846
5853
  this.grid.UpdateSheets(sheets, undefined, override_sheet || data.active_sheet);
5847
5854
 
5848
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
5849
- for (const [name, table] of this.model.tables.entries()) {
5850
- if (table.area.start.sheet_id) {
5855
+ for (const table of this.model.tables.values()) {
5856
+ if (table.area.start.sheet_id) {
5851
5857
  const sheet = model.sheets.Find(table.area.start.sheet_id);
5852
5858
  if (sheet) {
5853
5859
  for (let row = table.area.start.row; row <= table.area.end.row; row++) {
@@ -57,7 +57,6 @@ export type ResolutionFunction = () => void;
57
57
  */
58
58
  export class Dialog {
59
59
 
60
- // private model: NodeModel;
61
60
  private model: Record<string, HTMLElement> = {};
62
61
 
63
62
  private layout_element: HTMLElement;
@@ -192,6 +191,10 @@ export class Dialog {
192
191
 
193
192
  }
194
193
 
194
+ public Node(name: string): HTMLElement|undefined {
195
+ return this.model[name];
196
+ }
197
+
195
198
  public Update(options: Partial<MessageDialogOptions>, delta = true): void {
196
199
  if (delta) {
197
200
  options = { ...this.options_, ... options};
@@ -34,11 +34,11 @@ import { PixelsToColumnWidth } from './column-width';
34
34
  const XMLDeclaration = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n`;
35
35
 
36
36
  import { template } from './template-2';
37
- import type { SerializedModel, SerializedSheet } from 'treb-data-model';
37
+ import type { SerializedModel, SerializedSheet, DataValidation } from 'treb-data-model';
38
38
 
39
- import type { IArea, ICellAddress, CellValue, DataValidation, CellStyle,
39
+ import type { IArea, ICellAddress, CellValue, CellStyle,
40
40
  AnnotationLayout, Corner as LayoutCorner, Cell, Rectangle } from 'treb-base-types';
41
- import { Area, Cells, ValueType, Style, ValidationType } from 'treb-base-types';
41
+ import { Area, Cells, ValueType, Style } from 'treb-base-types';
42
42
 
43
43
  // import * as xmlparser from 'fast-xml-parser';
44
44
  import type { XmlBuilderOptions} from 'fast-xml-parser';
@@ -1417,10 +1417,12 @@ export class Exporter {
1417
1417
  const merges: Area[] = [];
1418
1418
  const tables: TableDescription[] = [];
1419
1419
 
1420
+ /*
1420
1421
  const validations: Array<{
1421
1422
  address: ICellAddress,
1422
1423
  validation: DataValidation,
1423
1424
  }> = [];
1425
+ */
1424
1426
 
1425
1427
  // --
1426
1428
 
@@ -1606,12 +1608,14 @@ export class Exporter {
1606
1608
  });
1607
1609
  }
1608
1610
 
1611
+ /*
1609
1612
  if (cell.validation && (cell.validation.type === ValidationType.List || cell.validation.type === ValidationType.Range)) {
1610
1613
  validations.push({
1611
1614
  address: {row: r, column: c},
1612
1615
  validation: cell.validation,
1613
1616
  });
1614
1617
  }
1618
+ */
1615
1619
 
1616
1620
  // short-circuit here
1617
1621
  if (cell.type === ValueType.formula && /^=?sparkline\./i.test(cell.value as string)) {
@@ -1929,37 +1933,46 @@ export class Exporter {
1929
1933
 
1930
1934
  // --- validation ----------------------------------------------------------
1931
1935
 
1932
- if (validations.length) {
1936
+ if (sheet.data_validations?.length) {
1933
1937
 
1934
1938
  dom.worksheet.dataValidations = {
1935
- a$: { count: validations.length },
1936
- dataValidation: validations.map(validation => {
1939
+ a$: { count: sheet.data_validations.length },
1940
+ dataValidation: sheet.data_validations.map(validation => {
1941
+
1942
+ const sqref = validation.target.map(target => {
1943
+ return new Area(target.start, target.end).spreadsheet_label;
1944
+ }).join(' ');
1945
+
1937
1946
  const entry: any = {
1938
1947
  a$: {
1939
1948
  type: 'list',
1940
1949
  allowBlank: 1,
1941
1950
  showInputMessage: 1,
1942
1951
  showErrorMessage: 1,
1943
- sqref: new Area(validation.address).spreadsheet_label,
1952
+ sqref, // : new Area(validation.address).spreadsheet_label,
1944
1953
  },
1945
1954
  };
1946
- if (validation.validation.type === ValidationType.Range) {
1955
+ if (validation.type === 'range') {
1947
1956
 
1948
1957
  const range: UnitRange = {
1949
1958
  id: 0,
1950
1959
  type: 'range',
1951
1960
  label: '', position: 0,
1952
1961
  start:
1953
- {...validation.validation.area.start, absolute_column: true, absolute_row: true, id: 0, label: '', position: 0, type: 'address', },
1962
+ {...validation.area.start, absolute_column: true, absolute_row: true, id: 0, label: '', position: 0, type: 'address', },
1954
1963
  end:
1955
- {...validation.validation.area.end, absolute_column: true, absolute_row: true, id: 0, label: '', position: 0, type: 'address', }
1964
+ {...validation.area.end, absolute_column: true, absolute_row: true, id: 0, label: '', position: 0, type: 'address', }
1956
1965
  ,
1957
1966
  }
1958
1967
 
1959
- if (typeof validation.validation.area.start.sheet_id !== 'undefined') {
1960
- range.start.sheet = sheet_name_map[validation.validation.area.start.sheet_id];
1968
+ console.info("AA", {validation});
1969
+
1970
+ if (typeof validation.area.start.sheet_id !== 'undefined') {
1971
+ range.start.sheet = sheet_name_map[validation.area.start.sheet_id];
1961
1972
  }
1962
1973
 
1974
+ console.info("m1");
1975
+
1963
1976
  /*
1964
1977
  const area = new Area(
1965
1978
  {...validation.validation.area.start, absolute_column: true, absolute_row: true},
@@ -1971,8 +1984,8 @@ export class Exporter {
1971
1984
  entry.formula1 = this.parser.Render(range);
1972
1985
 
1973
1986
  }
1974
- else if (validation.validation.type === ValidationType.List) {
1975
- entry.formula1 = `"${validation.validation.list.join(',')}"`;
1987
+ else if (validation.type === 'list') {
1988
+ entry.formula1 = `"${validation.list.join(',')}"`;
1976
1989
  }
1977
1990
  return entry;
1978
1991
  }),
@@ -30,8 +30,8 @@ import type { ParseResult } from 'treb-parser';
30
30
  import { Parser } from 'treb-parser';
31
31
  import type { RangeType, AddressType, HyperlinkType } from './address-type';
32
32
  import { is_range, ShiftRange, InRange, is_address } from './address-type';
33
- import type { ImportedSheetData, AnchoredAnnotation, CellParseResult, AnnotationLayout, Corner as LayoutCorner, ICellAddress, DataValidation, IArea, GradientStop, Color } from 'treb-base-types/src';
34
- import { ValidationType, type SerializedValueType } from 'treb-base-types/src';
33
+ import type { ImportedSheetData, AnchoredAnnotation, CellParseResult, AnnotationLayout, Corner as LayoutCorner, IArea, GradientStop, Color } from 'treb-base-types';
34
+ import type { SerializedValueType } from 'treb-base-types';
35
35
  import type { Sheet} from './workbook-sheet2';
36
36
  import { VisibleState } from './workbook-sheet2';
37
37
  import type { CellAnchor } from './drawing2/drawing2';
@@ -39,7 +39,7 @@ import { XMLUtils } from './xml-utils';
39
39
 
40
40
  // import { one_hundred_pixels } from './constants';
41
41
  import { ColumnWidthToPixels } from './column-width';
42
- import type { AnnotationType } from 'treb-data-model';
42
+ import type { DataValidation, AnnotationType } from 'treb-data-model';
43
43
  import { ZipWrapper } from './zip-wrapper';
44
44
  import type { ConditionalFormat } from 'treb-data-model';
45
45
 
@@ -99,7 +99,7 @@ export class Importer {
99
99
  arrays: RangeType[],
100
100
  merges: RangeType[],
101
101
  links: HyperlinkType[],
102
- validations: Array<{ address: ICellAddress, validation: DataValidation }>,
102
+ // validations: Array<{ address: ICellAddress, validation: DataValidation }>,
103
103
  ): CellParseResult | undefined {
104
104
 
105
105
  // must have, at minimum, an address (must be a single cell? FIXME)
@@ -285,12 +285,14 @@ export class Importer {
285
285
  }
286
286
  }
287
287
 
288
+ /*
288
289
  for (const validation of validations) {
289
290
  if (validation.address.row === shifted.row && validation.address.column === shifted.col) {
290
291
  result.validation = validation.validation;
291
292
  break;
292
293
  }
293
294
  }
295
+ */
294
296
 
295
297
  for (const range of merges) {
296
298
  if (InRange(range, shifted)) {
@@ -512,10 +514,15 @@ export class Importer {
512
514
  const conditional_formats: ConditionalFormat[] = [];
513
515
  const links: HyperlinkType[] = [];
514
516
  const row_styles: number[] = []; // may be sparse
517
+
518
+ /*
515
519
  const validations: Array<{
516
520
  address: ICellAddress,
517
521
  validation: DataValidation,
518
522
  }> = [];
523
+ */
524
+ const validations: DataValidation[] = [];
525
+
519
526
  const annotations: AnchoredAnnotation[] = [];
520
527
 
521
528
  const FindAll: (path: string) => any[] = XMLUtils.FindAll.bind(XMLUtils, sheet.sheet_data);
@@ -569,33 +576,68 @@ export class Importer {
569
576
  const formula = entry.formula1;
570
577
 
571
578
  if (ref && formula && type === 'list') {
572
- let address: ICellAddress|undefined;
579
+ // let address: ICellAddress|undefined;
573
580
  let validation: DataValidation|undefined;
574
581
  let parse_result = this.parser.Parse(ref);
582
+ const target: IArea[] = [];
575
583
 
576
584
  // apparently these are encoded as ranges for merged cells...
577
585
 
586
+ // NOTE: actually you can have a range, then validation applies
587
+ // to every cell in the range. also you can have multiple ranges,
588
+ // apparently separated by spaces.
589
+
578
590
  if (parse_result.expression) {
579
591
  if (parse_result.expression.type === 'address') {
580
- address = parse_result.expression;
592
+ // address = parse_result.expression;
593
+ target.push({start: parse_result.expression, end: parse_result.expression});
581
594
  }
582
595
  else if (parse_result.expression.type === 'range') {
583
- address = parse_result.expression.start;
596
+ // address = parse_result.expression.start;
597
+ target.push(parse_result.expression);
584
598
  }
585
599
  }
586
600
 
587
601
  parse_result = this.parser.Parse(formula);
602
+
588
603
  if (parse_result.expression) {
589
604
  if (parse_result.expression.type === 'range') {
590
605
  validation = {
591
- type: ValidationType.Range,
606
+ type: 'range',
592
607
  area: parse_result.expression,
608
+ target,
593
609
  };
594
610
  }
595
611
  else if (parse_result.expression.type === 'literal') {
596
612
  validation = {
597
- type: ValidationType.List,
613
+ type: 'list',
614
+ target,
598
615
  list: parse_result.expression.value.toString().split(/,/).map(value => {
616
+
617
+ // there are no formulas here. value is a string, separated
618
+ // by commas. there is no way to escape a comma (AFAICT; not
619
+ // official, but search). if you did want a comma, you'd need
620
+ // to use a range.
621
+
622
+ // but the uptake is split on commas. after that you can try
623
+ // to check for numbers or bools, but they will be in the string.
624
+
625
+ // I think excel might sort the entries? not sure. don't do it
626
+ // for now.
627
+
628
+ const num = Number(value);
629
+ if (!isNaN(num)) {
630
+ return num;
631
+ }
632
+ if (value.toLowerCase() === 'true') {
633
+ return true;
634
+ }
635
+ if (value.toLowerCase() === 'false') {
636
+ return false;
637
+ }
638
+ return value; // string
639
+
640
+ /*
599
641
  const tmp = this.parser.Parse(value);
600
642
 
601
643
  // if type is "group", that means we saw some spaces. this
@@ -612,13 +654,16 @@ export class Importer {
612
654
  return tmp.expression.name;
613
655
  }
614
656
  return undefined;
657
+ */
658
+
615
659
  }),
616
660
  };
617
661
  }
618
662
  }
619
663
 
620
- if (address && validation) {
621
- validations.push({address, validation});
664
+ if (target.length && validation) {
665
+ // validations.push({address, validation});
666
+ validations.push(validation);
622
667
  }
623
668
 
624
669
  }
@@ -730,7 +775,7 @@ export class Importer {
730
775
  if (!Array.isArray(cells)) { cells = [cells]; }
731
776
 
732
777
  for (const element of cells) {
733
- const cell = this.ParseCell(sheet, element, shared_formulae, arrays, merges, links, validations);
778
+ const cell = this.ParseCell(sheet, element, shared_formulae, arrays, merges, links); // , validations);
734
779
  if (cell) {
735
780
  data.push(cell);
736
781
  }
@@ -1178,6 +1223,7 @@ export class Importer {
1178
1223
  row_styles,
1179
1224
  annotations,
1180
1225
  conditional_formats,
1226
+ data_validations: validations,
1181
1227
  styles: this.workbook?.style_cache?.CellXfToStyles() || [],
1182
1228
  };
1183
1229
 
@@ -1295,19 +1295,8 @@ export abstract class BaseLayout {
1295
1295
  }
1296
1296
  }
1297
1297
 
1298
- /*
1299
- this.tooltip.style.fontFamily = theme.tooltip_font_face || '';
1300
- this.tooltip.style.fontSize = theme.tooltip_font_size ? `${theme.tooltip_font_size}pt` : '';
1301
- this.tooltip.style.backgroundColor = theme.tooltip_background || '';
1302
- this.tooltip.style.borderColor = theme.tooltip_background || ''; // for arrow
1303
- this.tooltip.style.color = theme.tooltip_color || '';
1304
- */
1305
-
1306
1298
  // TODO: dropdown caret
1307
1299
 
1308
- // this.dropdown_list.style.fontFamily = theme.cell_font || '';
1309
- // const font_size = (theme.cell_font_size_value || 10) * this.scale;
1310
- // this.dropdown_list.style.fontSize = (font_size) + (theme.cell_font_size_unit || 'pt');
1311
1300
  this.dropdown_list.style.font = Style.Font(theme.grid_cell || {});
1312
1301
 
1313
1302
  }
@@ -1415,6 +1404,8 @@ export abstract class BaseLayout {
1415
1404
  this.dropdown_list.style.left = `${target_rect.left + 2}px`;
1416
1405
  this.dropdown_list.style.minWidth = `${target_rect.width}px`;
1417
1406
 
1407
+ this.dropdown_list.style.fontSize = (this.scale.toFixed(2) + 'em');
1408
+
1418
1409
  this.dropdown_list.textContent = '';
1419
1410
  for (const value of list) {
1420
1411
  const entry = this.DOM.Div(undefined, this.dropdown_list);
@@ -40,7 +40,6 @@ import {
40
40
  ValueType,
41
41
  Localization,
42
42
  IsCellAddress,
43
- ValidationType,
44
43
  LoadThemeProperties,
45
44
  DefaultTheme,
46
45
  ComplexToString,
@@ -1465,20 +1464,22 @@ export class Grid extends GridBase {
1465
1464
  * and will render as a dropdown; the list can be a list of values or
1466
1465
  * a range reference.
1467
1466
  */
1468
- public SetValidation(target?: ICellAddress, data?: CellValue[]|IArea, error?: boolean): void {
1467
+ public SetValidation(target?: IArea, data?: CellValue[]|IArea, error?: boolean): void {
1469
1468
 
1470
1469
  if (!target) {
1471
1470
  if (this.primary_selection.empty) {
1472
1471
  throw new Error('invalid target in set validation');
1473
1472
  }
1474
- target = this.primary_selection.target;
1473
+ target = this.primary_selection.area;
1475
1474
  }
1476
1475
 
1476
+ const area = new Area(target.start, target.end);
1477
+
1477
1478
  // console.info({target, data});
1478
1479
 
1479
1480
  const command: DataValidationCommand = {
1480
1481
  key: CommandKey.DataValidation,
1481
- area: target,
1482
+ area: { start: area.start, end: area.end },
1482
1483
  error,
1483
1484
  };
1484
1485
 
@@ -1502,9 +1503,11 @@ export class Grid extends GridBase {
1502
1503
  //
1503
1504
 
1504
1505
  if (!this.primary_selection.empty &&
1505
- (!target.sheet_id || target.sheet_id === this.active_sheet.id) &&
1506
- (this.primary_selection.target.row === target.row) &&
1507
- (this.primary_selection.target.column === target.column)) {
1506
+ (!target.start.sheet_id || target.start.sheet_id === this.active_sheet.id) &&
1507
+ area.Contains(this.primary_selection.target)) {
1508
+
1509
+ // (this.primary_selection.target.row === target.start.row) &&
1510
+ // (this.primary_selection.target.column === target.start.column)) {
1508
1511
 
1509
1512
  // console.info('repaint selection');
1510
1513
 
@@ -4966,15 +4969,19 @@ export class Grid extends GridBase {
4966
4969
 
4967
4970
  }
4968
4971
 
4969
- if (cell.validation && cell.validation.error) {
4972
+ const validation = this.active_sheet.GetValidation(target)[0];
4973
+
4974
+ // only consider the first result
4975
+
4976
+ if (validation && validation.error) {
4970
4977
 
4971
4978
  let list: CellValue[]|undefined;
4972
4979
 
4973
- if (cell.validation.type === ValidationType.List) {
4974
- list = cell.validation.list;
4980
+ if (validation.type === 'list') {
4981
+ list = validation.list;
4975
4982
  }
4976
- else if (cell.validation.type === ValidationType.Range) {
4977
- list = this.GetValidationRange(cell.validation.area);
4983
+ else if (validation.type === 'range') {
4984
+ list = this.GetValidationRange(validation.area);
4978
4985
  }
4979
4986
 
4980
4987
  if (list && list.length) {
@@ -6216,15 +6223,19 @@ export class Grid extends GridBase {
6216
6223
  // sync up, so it would be a separate function but called at the
6217
6224
  // same time.
6218
6225
 
6219
- if (data.validation && !data.style?.locked) {
6226
+ // less true now that they're maintained separately
6227
+
6228
+ const validation = this.active_sheet.GetValidation(this.primary_selection.target)[0];
6229
+
6230
+ if (validation && !data.style?.locked) {
6220
6231
 
6221
6232
  let list: CellValue[] | undefined;
6222
6233
 
6223
- if (data.validation.type === ValidationType.List) {
6224
- list = data.validation.list;
6234
+ if (validation.type === 'list') {
6235
+ list = validation.list;
6225
6236
  }
6226
- else if (data.validation.type === ValidationType.Range) {
6227
- list = this.GetValidationRange(data.validation.area);
6237
+ else if (validation.type === 'range') {
6238
+ list = this.GetValidationRange(validation.area);
6228
6239
  }
6229
6240
 
6230
6241
  if (list && list.length) {
@@ -6541,7 +6552,7 @@ export class Grid extends GridBase {
6541
6552
  // tsv_row.push(cell.formatted);
6542
6553
 
6543
6554
  let text_value = '';
6544
- if (cell.calculated) {
6555
+ if (cell.calculated !== undefined) {
6545
6556
  if (cell.calculated_type === ValueType.complex) {
6546
6557
  text_value = ComplexToString(cell.calculated as Complex);
6547
6558
  }