@trebco/treb 29.3.4 → 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.
- package/dist/treb-spreadsheet-light.mjs +11 -11
- package/dist/treb-spreadsheet.mjs +11 -11
- package/dist/treb.d.ts +3 -25
- package/package.json +1 -1
- package/treb-base-types/src/area.ts +7 -0
- package/treb-base-types/src/cell.ts +2 -46
- package/treb-base-types/src/cells.ts +14 -8
- package/treb-base-types/src/import.ts +2 -2
- package/treb-calculator/src/calculator.ts +22 -12
- package/treb-calculator/src/dag/graph.ts +12 -3
- package/treb-calculator/src/expression-calculator.ts +66 -74
- package/treb-calculator/src/functions/base-functions.ts +2 -2
- package/treb-calculator/src/functions/statistics-functions.ts +31 -1
- package/treb-data-model/src/data-validation.ts +44 -0
- package/treb-data-model/src/data_model.ts +11 -7
- package/treb-data-model/src/index.ts +1 -1
- package/treb-data-model/src/named.ts +35 -10
- package/treb-data-model/src/sheet.ts +61 -0
- package/treb-data-model/src/sheet_types.ts +4 -0
- package/treb-embed/src/embedded-spreadsheet.ts +21 -15
- package/treb-embed/src/progress-dialog.ts +4 -1
- package/treb-export/src/export2.ts +27 -14
- package/treb-export/src/import2.ts +58 -12
- package/treb-grid/src/layout/base_layout.ts +2 -11
- package/treb-grid/src/types/grid.ts +29 -18
- package/treb-grid/src/types/grid_base.ts +83 -16
- package/treb-grid/src/types/grid_command.ts +2 -1
- package/treb-parser/src/parser.ts +22 -4
|
@@ -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,
|
|
34
|
-
import {
|
|
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:
|
|
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:
|
|
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 (
|
|
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?:
|
|
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.
|
|
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:
|
|
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
|
|
1507
|
-
|
|
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
|
-
|
|
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 (
|
|
4974
|
-
list =
|
|
4980
|
+
if (validation.type === 'list') {
|
|
4981
|
+
list = validation.list;
|
|
4975
4982
|
}
|
|
4976
|
-
else if (
|
|
4977
|
-
list = this.GetValidationRange(
|
|
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
|
-
|
|
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 (
|
|
6224
|
-
list =
|
|
6234
|
+
if (validation.type === 'list') {
|
|
6235
|
+
list = validation.list;
|
|
6225
6236
|
}
|
|
6226
|
-
else if (
|
|
6227
|
-
list = this.GetValidationRange(
|
|
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
|
}
|
|
@@ -37,11 +37,12 @@
|
|
|
37
37
|
|
|
38
38
|
import { EventSource } from 'treb-utils';
|
|
39
39
|
import type { DataModel, ConditionalFormat, // MacroFunction, SerializedModel, SerializedNamedExpression,
|
|
40
|
-
ViewModel
|
|
40
|
+
ViewModel,
|
|
41
|
+
DataValidation} from 'treb-data-model';
|
|
41
42
|
|
|
42
43
|
import type { Parser, UnitAddress} from 'treb-parser';
|
|
43
44
|
import { type ExpressionUnit, IllegalSheetNameRegex, ParseCSV, DecimalMarkType } from 'treb-parser';
|
|
44
|
-
import { Area, IsCellAddress,
|
|
45
|
+
import { Area, IsCellAddress, ValueType, DefaultTableSortOptions } from 'treb-base-types';
|
|
45
46
|
import type { ICellAddress, IArea, Cell, CellValue, CellStyle, Table, TableSortOptions, TableTheme, Complex, PatchOptions as PatchAreaOptions } from 'treb-base-types';
|
|
46
47
|
|
|
47
48
|
import { Sheet, type SerializeOptions, type Annotation } from 'treb-data-model';
|
|
@@ -922,34 +923,54 @@ export class GridBase {
|
|
|
922
923
|
|
|
923
924
|
protected SetValidationInternal(command: DataValidationCommand): void {
|
|
924
925
|
|
|
925
|
-
let cell: Cell|undefined;
|
|
926
|
-
|
|
927
926
|
const sheet = this.FindSheet(command.area);
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
cell = sheet.cells.GetCell(command.area, true);
|
|
927
|
+
if (!sheet) {
|
|
928
|
+
throw new Error('invalid sheet in set validation');
|
|
931
929
|
}
|
|
932
930
|
|
|
933
|
-
|
|
934
|
-
throw new Error('invalid cell in set validation');
|
|
935
|
-
}
|
|
931
|
+
const target = {start: command.area.start, end: command.area.end };
|
|
936
932
|
|
|
937
933
|
if (command.range) {
|
|
934
|
+
|
|
935
|
+
sheet.AddValidation({
|
|
936
|
+
type: 'range',
|
|
937
|
+
error: !!command.error,
|
|
938
|
+
area: command.range,
|
|
939
|
+
target: [target],
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
/*
|
|
938
943
|
cell.validation = {
|
|
939
944
|
type: ValidationType.Range,
|
|
940
945
|
area: command.range,
|
|
941
946
|
error: !!command.error,
|
|
942
947
|
};
|
|
948
|
+
*/
|
|
949
|
+
|
|
943
950
|
}
|
|
944
951
|
else if (command.list) {
|
|
952
|
+
|
|
953
|
+
sheet.AddValidation({
|
|
954
|
+
type: 'list',
|
|
955
|
+
error: !!command.error,
|
|
956
|
+
list: JSON.parse(JSON.stringify(command.list)),
|
|
957
|
+
target: [target],
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
/*
|
|
945
961
|
cell.validation = {
|
|
946
962
|
type: ValidationType.List,
|
|
947
963
|
list: JSON.parse(JSON.stringify(command.list)),
|
|
948
964
|
error: !!command.error,
|
|
949
965
|
}
|
|
966
|
+
*/
|
|
967
|
+
|
|
950
968
|
}
|
|
951
969
|
else {
|
|
952
|
-
cell.validation = undefined;
|
|
970
|
+
// cell.validation = undefined;
|
|
971
|
+
|
|
972
|
+
sheet.RemoveValidations(target);
|
|
973
|
+
|
|
953
974
|
}
|
|
954
975
|
|
|
955
976
|
}
|
|
@@ -2794,8 +2815,54 @@ export class GridBase {
|
|
|
2794
2815
|
/**
|
|
2795
2816
|
* patch sheet conditionals for insert/delete row/column operations.
|
|
2796
2817
|
* some of them may be deleted.
|
|
2818
|
+
*
|
|
2819
|
+
* UPDATE: using this routine to also patch data validations
|
|
2797
2820
|
*/
|
|
2798
|
-
protected
|
|
2821
|
+
protected PatchConditionalsAndValidations(options: PatchOptions) {
|
|
2822
|
+
|
|
2823
|
+
if (options.sheet.data_validation.length) {
|
|
2824
|
+
|
|
2825
|
+
const delete_list: Set<DataValidation> = new Set();
|
|
2826
|
+
for (const validation of options.sheet.data_validation) {
|
|
2827
|
+
|
|
2828
|
+
const targets: IArea[] = [];
|
|
2829
|
+
for (const area of validation.target) {
|
|
2830
|
+
const updated = Area.PatchArea(area, options);
|
|
2831
|
+
if (updated) {
|
|
2832
|
+
targets.push(updated);
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
if (targets.length > 0) {
|
|
2837
|
+
|
|
2838
|
+
validation.target = targets;
|
|
2839
|
+
|
|
2840
|
+
// format the range, if necessary
|
|
2841
|
+
|
|
2842
|
+
if (validation.type === 'range') {
|
|
2843
|
+
if (validation.area.start.sheet_id === options.sheet.id) {
|
|
2844
|
+
const updated = Area.PatchArea(validation.area, options);
|
|
2845
|
+
if (updated) {
|
|
2846
|
+
validation.area = updated;
|
|
2847
|
+
}
|
|
2848
|
+
else {
|
|
2849
|
+
delete_list.add(validation);
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
|
|
2854
|
+
}
|
|
2855
|
+
else {
|
|
2856
|
+
delete_list.add(validation);
|
|
2857
|
+
}
|
|
2858
|
+
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
if (delete_list.size) {
|
|
2862
|
+
options.sheet.data_validation = options.sheet.data_validation.filter(test => !delete_list.has(test));
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
}
|
|
2799
2866
|
|
|
2800
2867
|
if (options.sheet.conditional_formats?.length) {
|
|
2801
2868
|
|
|
@@ -2869,7 +2936,7 @@ export class GridBase {
|
|
|
2869
2936
|
}
|
|
2870
2937
|
|
|
2871
2938
|
// conditionals
|
|
2872
|
-
this.
|
|
2939
|
+
this.PatchConditionalsAndValidations({
|
|
2873
2940
|
sheet: target_sheet,
|
|
2874
2941
|
before_column: 0,
|
|
2875
2942
|
column_count: 0,
|
|
@@ -3217,7 +3284,7 @@ export class GridBase {
|
|
|
3217
3284
|
}
|
|
3218
3285
|
|
|
3219
3286
|
// conditionals
|
|
3220
|
-
this.
|
|
3287
|
+
this.PatchConditionalsAndValidations({
|
|
3221
3288
|
sheet: target_sheet,
|
|
3222
3289
|
before_column: command.before_column,
|
|
3223
3290
|
column_count: command.count,
|
|
@@ -4029,8 +4096,8 @@ export class GridBase {
|
|
|
4029
4096
|
// COEDITING: ok
|
|
4030
4097
|
|
|
4031
4098
|
this.SetValidationInternal(command);
|
|
4032
|
-
if (!command.area.sheet_id || command.area.sheet_id === this.active_sheet.id) {
|
|
4033
|
-
flags.render_area = Area.Join(new Area(command.area), flags.render_area);
|
|
4099
|
+
if (!command.area.start.sheet_id || command.area.start.sheet_id === this.active_sheet.id) {
|
|
4100
|
+
flags.render_area = Area.Join(new Area(command.area.start, command.area.end), flags.render_area);
|
|
4034
4101
|
}
|
|
4035
4102
|
break;
|
|
4036
4103
|
|
|
@@ -409,7 +409,7 @@ export class Parser {
|
|
|
409
409
|
for (let i = 0; i < n; i++) {
|
|
410
410
|
transposed[i] = [];
|
|
411
411
|
for (let j = 0; j < m; j++) {
|
|
412
|
-
transposed[i][j] = arr[j][i];
|
|
412
|
+
transposed[i][j] = arr[j] ? arr[j][i] : undefined;
|
|
413
413
|
}
|
|
414
414
|
}
|
|
415
415
|
|
|
@@ -2415,8 +2415,11 @@ export class Parser {
|
|
|
2415
2415
|
if (!c) return null;
|
|
2416
2416
|
position = c.position;
|
|
2417
2417
|
|
|
2418
|
+
// things that look like an address but have row 0 are legal
|
|
2419
|
+
// as names. so this should be a token if r === 0.
|
|
2420
|
+
|
|
2418
2421
|
const r = this.ConsumeAddressRow(position);
|
|
2419
|
-
if (!r) return null;
|
|
2422
|
+
if (!r) return null;
|
|
2420
2423
|
position = r.position;
|
|
2421
2424
|
|
|
2422
2425
|
const label = sheet ?
|
|
@@ -2460,7 +2463,11 @@ export class Parser {
|
|
|
2460
2463
|
|
|
2461
2464
|
/**
|
|
2462
2465
|
* consumes a row, possibly absolute ($). returns the numeric row
|
|
2463
|
-
* (0-based) and metadata
|
|
2466
|
+
* (0-based) and metadata.
|
|
2467
|
+
*
|
|
2468
|
+
* note that something like "X0" is a legal token, because 0 is not
|
|
2469
|
+
* a valid row. but at the same time it can't have a $ in it. although
|
|
2470
|
+
* maybe "X$0" is a token but not a valid name? dunno
|
|
2464
2471
|
*/
|
|
2465
2472
|
protected ConsumeAddressRow(position: number):
|
|
2466
2473
|
{
|
|
@@ -2484,7 +2491,18 @@ export class Parser {
|
|
|
2484
2491
|
else break;
|
|
2485
2492
|
}
|
|
2486
2493
|
|
|
2487
|
-
if (start === position)
|
|
2494
|
+
if (start === position) {
|
|
2495
|
+
return false;
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
// handle token X0. should ~maybe~ handle this only if !absolute
|
|
2499
|
+
// temp leaving this separate from the above test just so it's clear
|
|
2500
|
+
// what we are doing
|
|
2501
|
+
|
|
2502
|
+
if (value === 0) {
|
|
2503
|
+
return false;
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2488
2506
|
return { absolute, row: value - 1, position };
|
|
2489
2507
|
}
|
|
2490
2508
|
|