@trebco/treb 27.7.6 → 27.9.0
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.mjs +14 -14
- package/dist/treb.d.ts +21 -21
- package/notes/conditional-fomratring.md +29 -0
- package/package.json +1 -1
- package/treb-base-types/src/area.ts +181 -0
- package/treb-base-types/src/evaluate-options.ts +21 -0
- package/treb-base-types/src/gradient.ts +97 -0
- package/treb-base-types/src/import.ts +2 -1
- package/treb-base-types/src/index.ts +2 -0
- package/treb-calculator/src/calculator.ts +190 -28
- package/treb-calculator/src/dag/calculation_leaf_vertex.ts +97 -0
- package/treb-calculator/src/dag/graph.ts +10 -22
- package/treb-calculator/src/dag/{leaf_vertex.ts → state_leaf_vertex.ts} +3 -3
- package/treb-calculator/src/descriptors.ts +10 -3
- package/treb-calculator/src/expression-calculator.ts +1 -1
- package/treb-calculator/src/function-library.ts +25 -22
- package/treb-calculator/src/functions/base-functions.ts +166 -5
- package/treb-calculator/src/index.ts +6 -6
- package/treb-calculator/src/notifier-types.ts +1 -1
- package/treb-calculator/src/utilities.ts +2 -2
- package/treb-charts/src/util.ts +2 -2
- package/treb-embed/src/embedded-spreadsheet.ts +352 -41
- package/treb-export/src/export-worker/export-worker.ts +0 -13
- package/treb-export/src/export2.ts +187 -2
- package/treb-export/src/import2.ts +169 -4
- package/treb-export/src/workbook-style2.ts +56 -8
- package/treb-export/src/workbook2.ts +10 -1
- package/treb-grid/src/index.ts +2 -1
- package/treb-grid/src/layout/base_layout.ts +23 -15
- package/treb-grid/src/render/tile_renderer.ts +2 -1
- package/treb-grid/src/types/conditional_format.ts +168 -0
- package/treb-grid/src/types/grid.ts +5 -6
- package/treb-grid/src/types/grid_base.ts +186 -33
- package/treb-grid/src/types/sheet.ts +330 -26
- package/treb-grid/src/types/sheet_types.ts +4 -0
- /package/{README-shadow-DOM.md → notes/shadow-DOM.md} +0 -0
|
@@ -32,33 +32,47 @@ import type {
|
|
|
32
32
|
AnnotationViewData,
|
|
33
33
|
AnnotationType,
|
|
34
34
|
ExternalEditorConfig,
|
|
35
|
+
ConditionalFormatDuplicateValuesOptions,
|
|
36
|
+
ConditionalFormatDuplicateValues,
|
|
37
|
+
ConditionalFormatGradientOptions,
|
|
38
|
+
ConditionalFormat,
|
|
39
|
+
ConditionalFormatGradient,
|
|
40
|
+
ConditionalFormatExpression,
|
|
41
|
+
StandardGradient,
|
|
42
|
+
CondifionalFormatExpressionOptions,
|
|
43
|
+
ConditionalFormatCellMatchOptions,
|
|
44
|
+
ConditionalFormatCellMatch,
|
|
35
45
|
} from 'treb-grid';
|
|
36
46
|
|
|
37
47
|
import {
|
|
38
|
-
DataModel, Grid, BorderConstants, Sheet, ErrorCode, UA
|
|
48
|
+
DataModel, Grid, BorderConstants, Sheet, ErrorCode, UA,
|
|
49
|
+
StandardGradientsList,
|
|
39
50
|
} from 'treb-grid';
|
|
40
51
|
|
|
41
52
|
import {
|
|
42
53
|
Parser, DecimalMarkType,
|
|
43
54
|
ArgumentSeparatorType, QuotedSheetNameRegex } from 'treb-parser';
|
|
44
55
|
|
|
45
|
-
import { Calculator, type
|
|
56
|
+
import { Calculator, type LeafVertex } from 'treb-calculator';
|
|
46
57
|
|
|
47
58
|
import type {
|
|
48
59
|
ICellAddress,
|
|
60
|
+
EvaluateOptions,
|
|
49
61
|
IArea, CellValue, Point,
|
|
50
62
|
Complex, ExtendedUnion, IRectangle,
|
|
51
|
-
AddressReference, RangeReference, TableSortOptions, Table, TableTheme,
|
|
63
|
+
AddressReference, RangeReference, TableSortOptions, Table, TableTheme, GradientStop,
|
|
52
64
|
} from 'treb-base-types';
|
|
53
65
|
|
|
54
66
|
import {
|
|
55
67
|
IsArea, ThemeColorTable, ComplexToString, Rectangle, IsComplex, type CellStyle,
|
|
56
|
-
Localization, Style, type Color, ThemeColor2, IsCellAddress, Area, IsFlatData, IsFlatDataArray,
|
|
68
|
+
Localization, Style, type Color, ThemeColor2, IsCellAddress, Area, IsFlatData, IsFlatDataArray, Gradient, ValueType,
|
|
57
69
|
} from 'treb-base-types';
|
|
58
70
|
|
|
59
71
|
import { EventSource, Yield, ValidateURI } from 'treb-utils';
|
|
60
72
|
import { NumberFormatCache, ValueParser, NumberFormat } from 'treb-format';
|
|
61
73
|
|
|
74
|
+
|
|
75
|
+
|
|
62
76
|
// --- local -------------------------------------------------------------------
|
|
63
77
|
|
|
64
78
|
import { Dialog, DialogType } from './progress-dialog';
|
|
@@ -81,6 +95,7 @@ import type { SetRangeOptions } from 'treb-grid';
|
|
|
81
95
|
* the script so we can run it as a worker.
|
|
82
96
|
*/
|
|
83
97
|
import * as export_worker_script from 'worker:../../treb-export/src/export-worker/index.worker';
|
|
98
|
+
import { StateLeafVertex } from 'treb-calculator/src/dag/state_leaf_vertex';
|
|
84
99
|
|
|
85
100
|
// --- types -------------------------------------------------------------------
|
|
86
101
|
|
|
@@ -1251,6 +1266,265 @@ export class EmbeddedSpreadsheet {
|
|
|
1251
1266
|
|
|
1252
1267
|
}
|
|
1253
1268
|
|
|
1269
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1270
|
+
//
|
|
1271
|
+
// conditional formatting API (WIP)
|
|
1272
|
+
//
|
|
1273
|
+
|
|
1274
|
+
/**
|
|
1275
|
+
* list conditional formats. uses the active sheet by default, or pass a
|
|
1276
|
+
* sheet name or id.
|
|
1277
|
+
*
|
|
1278
|
+
* @internal
|
|
1279
|
+
*/
|
|
1280
|
+
public ListConditionalFormats(sheet?: number|string) {
|
|
1281
|
+
|
|
1282
|
+
const target = (typeof sheet === 'undefined') ?
|
|
1283
|
+
this.grid.active_sheet :
|
|
1284
|
+
this.model.sheets.Find(sheet);
|
|
1285
|
+
|
|
1286
|
+
return target?.conditional_formats || [];
|
|
1287
|
+
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
/** @internal */
|
|
1291
|
+
public ConditionalFormatDuplicateValues(range: RangeReference|undefined, options: ConditionalFormatDuplicateValuesOptions): ConditionalFormat {
|
|
1292
|
+
|
|
1293
|
+
if (range === undefined) {
|
|
1294
|
+
const ref = this.GetSelectionReference();
|
|
1295
|
+
if (ref.empty) {
|
|
1296
|
+
throw new Error('invalid range (no selection)');
|
|
1297
|
+
}
|
|
1298
|
+
range = ref.area;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
return this.AddConditionalFormat({
|
|
1302
|
+
type: 'duplicate-values',
|
|
1303
|
+
area: this.model.ResolveArea(range, this.grid.active_sheet),
|
|
1304
|
+
...options,
|
|
1305
|
+
});
|
|
1306
|
+
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
/**
|
|
1310
|
+
* @internal
|
|
1311
|
+
*/
|
|
1312
|
+
public ConditionalFormatGradient(range: RangeReference|undefined, options: ConditionalFormatGradientOptions|StandardGradient): ConditionalFormat {
|
|
1313
|
+
|
|
1314
|
+
if (range === undefined) {
|
|
1315
|
+
const ref = this.GetSelectionReference();
|
|
1316
|
+
if (ref.empty) {
|
|
1317
|
+
throw new Error('invalid range (no selection)');
|
|
1318
|
+
}
|
|
1319
|
+
range = ref.area;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
const area = this.model.ResolveArea(range, this.grid.active_sheet);
|
|
1323
|
+
|
|
1324
|
+
const format: ConditionalFormatGradient = (typeof options === 'object') ?
|
|
1325
|
+
{
|
|
1326
|
+
type: 'gradient', area, ...options,
|
|
1327
|
+
} :
|
|
1328
|
+
{
|
|
1329
|
+
type: 'gradient', area, ...StandardGradientsList[options]
|
|
1330
|
+
};
|
|
1331
|
+
|
|
1332
|
+
this.AddConditionalFormat(format);
|
|
1333
|
+
return format;
|
|
1334
|
+
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
/** @internal */
|
|
1338
|
+
public ConditionalFormatCellMatch(range: RangeReference|undefined, options: ConditionalFormatCellMatchOptions): ConditionalFormat {
|
|
1339
|
+
|
|
1340
|
+
if (range === undefined) {
|
|
1341
|
+
const ref = this.GetSelectionReference();
|
|
1342
|
+
if (ref.empty) {
|
|
1343
|
+
throw new Error('invalid range (no selection)');
|
|
1344
|
+
}
|
|
1345
|
+
range = ref.area;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
const area = this.model.ResolveArea(range, this.grid.active_sheet);
|
|
1349
|
+
|
|
1350
|
+
const format: ConditionalFormatCellMatch = {
|
|
1351
|
+
type: 'cell-match',
|
|
1352
|
+
area,
|
|
1353
|
+
...options,
|
|
1354
|
+
};
|
|
1355
|
+
|
|
1356
|
+
// we need to calculate the formula once, to get an initial state
|
|
1357
|
+
// update: internal
|
|
1358
|
+
// let result = this.Evaluate(this.Unresolve(area, true, false) + ' ' + options.expression, options.options);
|
|
1359
|
+
|
|
1360
|
+
// ... apply ...
|
|
1361
|
+
|
|
1362
|
+
this.AddConditionalFormat(format);
|
|
1363
|
+
return format;
|
|
1364
|
+
|
|
1365
|
+
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
/**
|
|
1369
|
+
* @internal
|
|
1370
|
+
*/
|
|
1371
|
+
public ConditionalFormatExpression(range: RangeReference|undefined, options: CondifionalFormatExpressionOptions): ConditionalFormat {
|
|
1372
|
+
|
|
1373
|
+
if (range === undefined) {
|
|
1374
|
+
const ref = this.GetSelectionReference();
|
|
1375
|
+
if (ref.empty) {
|
|
1376
|
+
throw new Error('invalid range (no selection)');
|
|
1377
|
+
}
|
|
1378
|
+
range = ref.area;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
const area = this.model.ResolveArea(range, this.grid.active_sheet);
|
|
1382
|
+
|
|
1383
|
+
const format: ConditionalFormatExpression = {
|
|
1384
|
+
type: 'expression',
|
|
1385
|
+
area,
|
|
1386
|
+
...options,
|
|
1387
|
+
};
|
|
1388
|
+
|
|
1389
|
+
/*
|
|
1390
|
+
// we need to calculate the formula once, to get an initial state
|
|
1391
|
+
let result = this.Evaluate(options.expression, options.options);
|
|
1392
|
+
|
|
1393
|
+
if (Array.isArray(result)) {
|
|
1394
|
+
result = result[0][0];
|
|
1395
|
+
}
|
|
1396
|
+
const applied = !!result;
|
|
1397
|
+
|
|
1398
|
+
this.AddConditionalFormat({...format, applied });
|
|
1399
|
+
*/
|
|
1400
|
+
|
|
1401
|
+
this.AddConditionalFormat(format);
|
|
1402
|
+
|
|
1403
|
+
return format;
|
|
1404
|
+
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
/**
|
|
1408
|
+
* add a conditional format
|
|
1409
|
+
*
|
|
1410
|
+
* @internal
|
|
1411
|
+
*/
|
|
1412
|
+
public AddConditionalFormat(format: ConditionalFormat) {
|
|
1413
|
+
|
|
1414
|
+
const sheet = this.model.sheets.Find(format.area.start.sheet_id||0);
|
|
1415
|
+
|
|
1416
|
+
if (!sheet) {
|
|
1417
|
+
throw new Error('invalid reference in format');
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
sheet.conditional_formats.push(format);
|
|
1421
|
+
|
|
1422
|
+
this.calculator.UpdateConditionals(format, sheet);
|
|
1423
|
+
|
|
1424
|
+
// call update if it's the current sheet
|
|
1425
|
+
this.ApplyConditionalFormats(sheet, sheet === this.grid.active_sheet);
|
|
1426
|
+
|
|
1427
|
+
this.PushUndo();
|
|
1428
|
+
|
|
1429
|
+
// fluent
|
|
1430
|
+
return format;
|
|
1431
|
+
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
/**
|
|
1435
|
+
* remove conditional format
|
|
1436
|
+
*
|
|
1437
|
+
* @internal
|
|
1438
|
+
*/
|
|
1439
|
+
public RemoveConditionalFormat(format: ConditionalFormat) {
|
|
1440
|
+
const area = format.area;
|
|
1441
|
+
const sheet = area.start.sheet_id ? this.model.sheets.Find(area.start.sheet_id) : this.grid.active_sheet;
|
|
1442
|
+
|
|
1443
|
+
if (!sheet) {
|
|
1444
|
+
throw new Error('invalid reference in format');
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
let count = 0;
|
|
1448
|
+
sheet.conditional_formats = sheet.conditional_formats.filter(test => {
|
|
1449
|
+
if (test === format) {
|
|
1450
|
+
count++;
|
|
1451
|
+
this.calculator.RemoveConditional(test);
|
|
1452
|
+
return false;
|
|
1453
|
+
}
|
|
1454
|
+
return true;
|
|
1455
|
+
});
|
|
1456
|
+
|
|
1457
|
+
if (count) {
|
|
1458
|
+
sheet.FlushConditionalFormats();
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
// we want to call update if it's the current sheet,
|
|
1462
|
+
// but we want a full repaint
|
|
1463
|
+
|
|
1464
|
+
this.ApplyConditionalFormats(sheet, false);
|
|
1465
|
+
|
|
1466
|
+
if (sheet === this.grid.active_sheet) {
|
|
1467
|
+
this.grid.Update(true);
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
if (count) {
|
|
1471
|
+
this.PushUndo();
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
/**
|
|
1477
|
+
* clear conditional formats from the target range (or currently selected
|
|
1478
|
+
* range). we operate on format objects, meaning we'll remove the whole
|
|
1479
|
+
* format object rather than clip the area.
|
|
1480
|
+
*
|
|
1481
|
+
* @internal
|
|
1482
|
+
*/
|
|
1483
|
+
public RemoveConditionalFormats(range?: RangeReference) {
|
|
1484
|
+
|
|
1485
|
+
if (range === undefined) {
|
|
1486
|
+
const ref = this.GetSelectionReference();
|
|
1487
|
+
if (ref.empty) {
|
|
1488
|
+
throw new Error('invalid range (no selection)');
|
|
1489
|
+
}
|
|
1490
|
+
range = ref.area;
|
|
1491
|
+
}
|
|
1492
|
+
const area = this.model.ResolveArea(range, this.grid.active_sheet);
|
|
1493
|
+
const sheet = area.start.sheet_id ? this.model.sheets.Find(area.start.sheet_id) : this.grid.active_sheet;
|
|
1494
|
+
|
|
1495
|
+
if (sheet) {
|
|
1496
|
+
let count = 0;
|
|
1497
|
+
|
|
1498
|
+
sheet.conditional_formats = sheet.conditional_formats.filter(test => {
|
|
1499
|
+
const compare = new Area(test.area.start, test.area.end);
|
|
1500
|
+
if (compare.Intersects(area)) {
|
|
1501
|
+
count++;
|
|
1502
|
+
this.calculator.RemoveConditional(test);
|
|
1503
|
+
return false;
|
|
1504
|
+
}
|
|
1505
|
+
return true;
|
|
1506
|
+
});
|
|
1507
|
+
|
|
1508
|
+
if (count) {
|
|
1509
|
+
|
|
1510
|
+
sheet.FlushConditionalFormats();
|
|
1511
|
+
|
|
1512
|
+
this.ApplyConditionalFormats(sheet, false);
|
|
1513
|
+
|
|
1514
|
+
if (sheet === this.grid.active_sheet) {
|
|
1515
|
+
this.grid.Update(true);
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
this.PushUndo();
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
1527
|
+
|
|
1254
1528
|
/**
|
|
1255
1529
|
* @internal
|
|
1256
1530
|
*/
|
|
@@ -1794,6 +2068,19 @@ export class EmbeddedSpreadsheet {
|
|
|
1794
2068
|
|
|
1795
2069
|
this.UpdateDocumentStyles();
|
|
1796
2070
|
|
|
2071
|
+
// we need to flush conditional formats that use theme colors
|
|
2072
|
+
// (I guess we're just flushing everybody?)
|
|
2073
|
+
|
|
2074
|
+
for (const sheet of this.model.sheets.list) {
|
|
2075
|
+
for (const format of sheet.conditional_formats) {
|
|
2076
|
+
format.internal = undefined;
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
this.calculator.UpdateConditionals();
|
|
2081
|
+
this.ApplyConditionalFormats(this.grid.active_sheet, false);
|
|
2082
|
+
this.grid.Update(true);
|
|
2083
|
+
|
|
1797
2084
|
}
|
|
1798
2085
|
|
|
1799
2086
|
/**
|
|
@@ -2954,11 +3241,11 @@ export class EmbeddedSpreadsheet {
|
|
|
2954
3241
|
// FIXME: optional? parameter? (...)
|
|
2955
3242
|
|
|
2956
3243
|
if (data.rendered_values && !options.recalculate) {
|
|
2957
|
-
this.grid.Update();
|
|
2958
3244
|
this.calculator.RebuildClean(true);
|
|
3245
|
+
this.ApplyConditionalFormats(this.grid.active_sheet, false);
|
|
3246
|
+
this.grid.Update();
|
|
2959
3247
|
}
|
|
2960
3248
|
else {
|
|
2961
|
-
// console.info('load recalc');
|
|
2962
3249
|
this.Recalculate();
|
|
2963
3250
|
}
|
|
2964
3251
|
|
|
@@ -3248,6 +3535,7 @@ export class EmbeddedSpreadsheet {
|
|
|
3248
3535
|
}
|
|
3249
3536
|
|
|
3250
3537
|
this.calculator.Calculate(area);
|
|
3538
|
+
this.ApplyConditionalFormats(this.grid.active_sheet, false);
|
|
3251
3539
|
|
|
3252
3540
|
this.grid.Update(true); // , area);
|
|
3253
3541
|
this.UpdateAnnotations();
|
|
@@ -3432,6 +3720,9 @@ export class EmbeddedSpreadsheet {
|
|
|
3432
3720
|
ref = resolved;
|
|
3433
3721
|
}
|
|
3434
3722
|
|
|
3723
|
+
return this.calculator.Unresolve(ref, this.grid.active_sheet, qualified, named);
|
|
3724
|
+
|
|
3725
|
+
/*
|
|
3435
3726
|
let range = '';
|
|
3436
3727
|
const area = IsCellAddress(ref) ? new Area(ref) : new Area(ref.start, ref.end);
|
|
3437
3728
|
|
|
@@ -3457,10 +3748,11 @@ export class EmbeddedSpreadsheet {
|
|
|
3457
3748
|
// the active selection must be on the active sheet? (...)
|
|
3458
3749
|
|
|
3459
3750
|
const sheet_id = area.start.sheet_id || this.grid.active_sheet.id;
|
|
3460
|
-
const sheet_name = this.ResolveSheetName(sheet_id, true);
|
|
3751
|
+
const sheet_name = this.calculator.ResolveSheetName(sheet_id, true);
|
|
3461
3752
|
|
|
3462
3753
|
return sheet_name ? sheet_name + '!' + range : range;
|
|
3463
|
-
|
|
3754
|
+
*/
|
|
3755
|
+
|
|
3464
3756
|
}
|
|
3465
3757
|
|
|
3466
3758
|
/**
|
|
@@ -3482,7 +3774,7 @@ export class EmbeddedSpreadsheet {
|
|
|
3482
3774
|
|
|
3483
3775
|
return this.calculator.Evaluate(
|
|
3484
3776
|
expression, this.grid.active_sheet, options);
|
|
3485
|
-
|
|
3777
|
+
|
|
3486
3778
|
}
|
|
3487
3779
|
|
|
3488
3780
|
/**
|
|
@@ -3522,7 +3814,7 @@ export class EmbeddedSpreadsheet {
|
|
|
3522
3814
|
// the active selection must be on the active sheet? (...)
|
|
3523
3815
|
|
|
3524
3816
|
const sheet_id = ref.area.start.sheet_id || this.grid.active_sheet.id;
|
|
3525
|
-
const sheet_name = this.ResolveSheetName(sheet_id, true);
|
|
3817
|
+
const sheet_name = this.calculator.ResolveSheetName(sheet_id, true);
|
|
3526
3818
|
|
|
3527
3819
|
return sheet_name ? sheet_name + '!' + range : range;
|
|
3528
3820
|
|
|
@@ -3940,6 +4232,47 @@ export class EmbeddedSpreadsheet {
|
|
|
3940
4232
|
|
|
3941
4233
|
// --- internal (protected) methods ------------------------------------------
|
|
3942
4234
|
|
|
4235
|
+
/**
|
|
4236
|
+
*
|
|
4237
|
+
*/
|
|
4238
|
+
protected ApplyConditionalFormats(sheet: Sheet, call_update: boolean) {
|
|
4239
|
+
|
|
4240
|
+
// const sheet = this.grid.active_sheet;
|
|
4241
|
+
const areas: IArea[] = [];
|
|
4242
|
+
|
|
4243
|
+
if (sheet.conditional_formats.length || sheet.flush_conditional_formats) {
|
|
4244
|
+
|
|
4245
|
+
for (const entry of sheet.conditional_formats) {
|
|
4246
|
+
areas.push(entry.area);
|
|
4247
|
+
|
|
4248
|
+
// NOTE: we're (optionally) adding the gradient here, instead
|
|
4249
|
+
// of when it's created, because we might want to flush this
|
|
4250
|
+
// from time to time. specifically, because gradient might use
|
|
4251
|
+
// theme colors, we need to flush it when the theme is updated.
|
|
4252
|
+
|
|
4253
|
+
// so don't move it, even though it is tempting. or rewrite to
|
|
4254
|
+
// update on theme changes.
|
|
4255
|
+
|
|
4256
|
+
if (entry.type === 'gradient') {
|
|
4257
|
+
if (!entry.internal) {
|
|
4258
|
+
entry.internal = {};
|
|
4259
|
+
}
|
|
4260
|
+
if (!entry.internal.gradient) {
|
|
4261
|
+
entry.internal.gradient = new Gradient(entry.stops, this.grid.theme, entry.color_space);
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
|
|
4266
|
+
sheet.ApplyConditionalFormats();
|
|
4267
|
+
|
|
4268
|
+
}
|
|
4269
|
+
|
|
4270
|
+
if (call_update) {
|
|
4271
|
+
this.grid.Update(true, areas);
|
|
4272
|
+
}
|
|
4273
|
+
|
|
4274
|
+
}
|
|
4275
|
+
|
|
3943
4276
|
protected ResolveTable(reference: RangeReference): Table|undefined {
|
|
3944
4277
|
|
|
3945
4278
|
let table: Table|undefined = undefined;
|
|
@@ -4044,6 +4377,11 @@ export class EmbeddedSpreadsheet {
|
|
|
4044
4377
|
|
|
4045
4378
|
this.InflateAnnotations();
|
|
4046
4379
|
|
|
4380
|
+
// and conditional formats
|
|
4381
|
+
|
|
4382
|
+
this.calculator.UpdateConditionals();
|
|
4383
|
+
this.ApplyConditionalFormats(this.grid.active_sheet, false);
|
|
4384
|
+
|
|
4047
4385
|
}
|
|
4048
4386
|
else {
|
|
4049
4387
|
return reject('unknown error (missing data)');
|
|
@@ -4164,6 +4502,9 @@ export class EmbeddedSpreadsheet {
|
|
|
4164
4502
|
|
|
4165
4503
|
this.UpdateAnnotations();
|
|
4166
4504
|
|
|
4505
|
+
this.calculator.UpdateConditionals();
|
|
4506
|
+
this.ApplyConditionalFormats(event.activate, true);
|
|
4507
|
+
|
|
4167
4508
|
}
|
|
4168
4509
|
|
|
4169
4510
|
protected HandleDrag(event: DragEvent): void {
|
|
@@ -4556,7 +4897,7 @@ export class EmbeddedSpreadsheet {
|
|
|
4556
4897
|
protected UpdateAnnotations(): void {
|
|
4557
4898
|
for (const annotation of this.grid.active_sheet.annotations) {
|
|
4558
4899
|
if (annotation.temp.vertex) {
|
|
4559
|
-
const vertex = annotation.temp.vertex as
|
|
4900
|
+
const vertex = annotation.temp.vertex as StateLeafVertex;
|
|
4560
4901
|
if (vertex.state_id !== annotation.temp.state) {
|
|
4561
4902
|
annotation.temp.state = vertex.state_id;
|
|
4562
4903
|
|
|
@@ -5436,35 +5777,5 @@ export class EmbeddedSpreadsheet {
|
|
|
5436
5777
|
}
|
|
5437
5778
|
}
|
|
5438
5779
|
|
|
5439
|
-
/**
|
|
5440
|
-
* this is only used in one place, can we just inline?
|
|
5441
|
-
* [A: seems like it might be useful, though]
|
|
5442
|
-
*
|
|
5443
|
-
* @param id
|
|
5444
|
-
* @param quote
|
|
5445
|
-
* @returns
|
|
5446
|
-
*/
|
|
5447
|
-
protected ResolveSheetName(id: number, quote = false): string | undefined {
|
|
5448
|
-
const sheet = this.model.sheets.Find(id);
|
|
5449
|
-
if (sheet) {
|
|
5450
|
-
if (quote && QuotedSheetNameRegex.test(sheet.name)) {
|
|
5451
|
-
return `'${sheet.name}'`;
|
|
5452
|
-
}
|
|
5453
|
-
return sheet.name;
|
|
5454
|
-
}
|
|
5455
|
-
|
|
5456
|
-
/*
|
|
5457
|
-
for (const sheet of this.grid.model.sheets) {
|
|
5458
|
-
if (sheet.id === id) {
|
|
5459
|
-
if (quote && QuotedSheetNameRegex.test(sheet.name)) {
|
|
5460
|
-
return `'${sheet.name}'`;
|
|
5461
|
-
}
|
|
5462
|
-
return sheet.name;
|
|
5463
|
-
}
|
|
5464
|
-
}
|
|
5465
|
-
*/
|
|
5466
|
-
|
|
5467
|
-
return undefined;
|
|
5468
|
-
}
|
|
5469
5780
|
|
|
5470
5781
|
}
|
|
@@ -40,19 +40,6 @@ const ExportSheets = async (data: any) => {
|
|
|
40
40
|
ctx.postMessage({ status: 'complete', blob: corrected });
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
/*
|
|
44
|
-
if (data.sheet) {
|
|
45
|
-
await exporter.Init();
|
|
46
|
-
await exporter.ExportSheets(data.sheet);
|
|
47
|
-
const blob = await exporter.AsBlob(1);
|
|
48
|
-
|
|
49
|
-
// correct the mime type for firefox
|
|
50
|
-
const corrected = (blob as Blob).slice(0, (blob as Blob).size,
|
|
51
|
-
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
|
52
|
-
|
|
53
|
-
ctx.postMessage({ status: 'complete', blob: corrected });
|
|
54
|
-
}
|
|
55
|
-
*/
|
|
56
43
|
};
|
|
57
44
|
|
|
58
45
|
const ImportSheet = async (data: any) => {
|