@trebco/treb 29.3.4 → 29.5.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-light.mjs +12 -12
- package/dist/treb-spreadsheet.mjs +12 -12
- package/dist/treb.d.ts +36 -41
- 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/gradient.ts +2 -2
- package/treb-base-types/src/import.ts +2 -2
- package/treb-base-types/src/style.ts +79 -6
- package/treb-base-types/src/theme.ts +24 -15
- 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/sparkline.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 +75 -15
- package/treb-data-model/src/sheet_types.ts +4 -0
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +7 -3
- package/treb-embed/src/embedded-spreadsheet.ts +50 -28
- package/treb-embed/src/progress-dialog.ts +4 -1
- package/treb-embed/src/types.ts +9 -0
- package/treb-export/src/drawing2/chart2.ts +20 -38
- package/treb-export/src/drawing2/drawing2.ts +2 -107
- package/treb-export/src/export-worker/export-worker.ts +1 -1
- package/treb-export/src/{export2.ts → export.ts} +439 -628
- package/treb-export/src/import2.ts +63 -26
- package/treb-export/src/workbook-style2.ts +16 -14
- package/treb-export/src/workbook2.ts +2 -18
- package/treb-export/src/xml-utils.ts +50 -2
- package/treb-export/src/zip-wrapper.ts +1 -1
- package/treb-grid/src/editors/overlay_editor.ts +3 -3
- package/treb-grid/src/layout/base_layout.ts +5 -14
- package/treb-grid/src/render/tile_renderer.ts +49 -48
- package/treb-grid/src/types/grid.ts +164 -26
- package/treb-grid/src/types/grid_base.ts +93 -17
- package/treb-grid/src/types/grid_command.ts +2 -1
- package/treb-parser/src/parser-types.ts +10 -0
- package/treb-parser/src/parser.ts +55 -17
|
@@ -25,7 +25,7 @@ import type { ICellAddress,
|
|
|
25
25
|
CellStyle,
|
|
26
26
|
Theme,
|
|
27
27
|
HorizontalAlign} from 'treb-base-types';
|
|
28
|
-
import { TextPartFlag, Style, ValueType, Area, Rectangle,
|
|
28
|
+
import { TextPartFlag, Style, ValueType, Area, Rectangle, ResolveThemeColor, IsDefinedColor } from 'treb-base-types';
|
|
29
29
|
|
|
30
30
|
import type { Tile } from '../types/tile';
|
|
31
31
|
import { FontMetricsCache as FontMetricsCache2 } from '../util/fontmetrics2';
|
|
@@ -307,7 +307,7 @@ export class TileRenderer {
|
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
context.setTransform(scale, 0, 0, scale, 0, 0);
|
|
310
|
-
context.fillStyle = this.theme.headers?.fill ?
|
|
310
|
+
context.fillStyle = this.theme.headers?.fill ? ResolveThemeColor(this.theme, this.theme.headers.fill) : '';
|
|
311
311
|
|
|
312
312
|
context.fillRect(0, 0, x, header_size.y);
|
|
313
313
|
context.fillRect(0, 0, header_size.x, y);
|
|
@@ -354,7 +354,7 @@ export class TileRenderer {
|
|
|
354
354
|
context.textBaseline = 'middle';
|
|
355
355
|
context.font = Style.Font(this.theme.headers||{}, this.layout.scale);
|
|
356
356
|
|
|
357
|
-
context.fillStyle =
|
|
357
|
+
context.fillStyle = ResolveThemeColor(this.theme, this.theme.headers?.text);
|
|
358
358
|
|
|
359
359
|
if (this.view.active_sheet.freeze.rows && this.layout.header_offset.x > 1) {
|
|
360
360
|
|
|
@@ -407,7 +407,7 @@ export class TileRenderer {
|
|
|
407
407
|
return;
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
-
context.fillStyle =
|
|
410
|
+
context.fillStyle = ResolveThemeColor(this.theme, this.theme.headers?.text, 0);
|
|
411
411
|
|
|
412
412
|
context.beginPath();
|
|
413
413
|
|
|
@@ -434,7 +434,7 @@ export class TileRenderer {
|
|
|
434
434
|
return;
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
-
context.fillStyle =
|
|
437
|
+
context.fillStyle = ResolveThemeColor(this.theme, this.theme.headers?.text, 0);
|
|
438
438
|
|
|
439
439
|
context.beginPath();
|
|
440
440
|
|
|
@@ -473,7 +473,7 @@ export class TileRenderer {
|
|
|
473
473
|
context.textBaseline = 'middle';
|
|
474
474
|
context.font = Style.Font(this.theme.headers||{}, this.layout.scale);
|
|
475
475
|
|
|
476
|
-
context.fillStyle = this.theme.headers?.fill ?
|
|
476
|
+
context.fillStyle = this.theme.headers?.fill ? ResolveThemeColor(this.theme, this.theme.headers.fill) : '';
|
|
477
477
|
context.fillRect(0, 0, tile.logical_size.width, this.layout.header_offset.y);
|
|
478
478
|
|
|
479
479
|
// context.strokeStyle = this.theme.grid_color || '';
|
|
@@ -507,7 +507,7 @@ export class TileRenderer {
|
|
|
507
507
|
|
|
508
508
|
const context = tile.getContext('2d', { alpha: false });
|
|
509
509
|
if (!context) continue;
|
|
510
|
-
context.fillStyle = this.theme.headers?.fill ?
|
|
510
|
+
context.fillStyle = this.theme.headers?.fill ? ResolveThemeColor(this.theme, this.theme.headers.fill) : '';
|
|
511
511
|
|
|
512
512
|
context.setTransform(scale, 0, 0, scale, 0, 0);
|
|
513
513
|
|
|
@@ -1065,7 +1065,7 @@ export class TileRenderer {
|
|
|
1065
1065
|
protected ResolveColors(style: CellStyle): CellStyle {
|
|
1066
1066
|
|
|
1067
1067
|
const resolved = {...style};
|
|
1068
|
-
resolved.text = { text:
|
|
1068
|
+
resolved.text = { text: ResolveThemeColor(this.theme, style.text, 1) };
|
|
1069
1069
|
|
|
1070
1070
|
// TODO: other colors
|
|
1071
1071
|
|
|
@@ -1126,7 +1126,7 @@ export class TileRenderer {
|
|
|
1126
1126
|
|
|
1127
1127
|
// paint top background
|
|
1128
1128
|
|
|
1129
|
-
let color =
|
|
1129
|
+
let color = ResolveThemeColor(this.theme, numpad[8].fill);
|
|
1130
1130
|
if (color) {
|
|
1131
1131
|
context.fillStyle = color
|
|
1132
1132
|
context.fillRect(left + 0, top - 1, width, 1);
|
|
@@ -1134,7 +1134,7 @@ export class TileRenderer {
|
|
|
1134
1134
|
|
|
1135
1135
|
// paint left background
|
|
1136
1136
|
|
|
1137
|
-
color =
|
|
1137
|
+
color = ResolveThemeColor(this.theme, numpad[4].fill);
|
|
1138
1138
|
if (color) {
|
|
1139
1139
|
context.fillStyle = color
|
|
1140
1140
|
context.fillRect(left - 1, top, 1, height);
|
|
@@ -1142,7 +1142,7 @@ export class TileRenderer {
|
|
|
1142
1142
|
|
|
1143
1143
|
// paint our background. note this one goes up, left
|
|
1144
1144
|
|
|
1145
|
-
color =
|
|
1145
|
+
color = ResolveThemeColor(this.theme, style.fill);
|
|
1146
1146
|
if (color) {
|
|
1147
1147
|
context.fillStyle = color;
|
|
1148
1148
|
context.fillRect(left - 1, top - 1, width + 1, height + 1);
|
|
@@ -1150,7 +1150,7 @@ export class TileRenderer {
|
|
|
1150
1150
|
|
|
1151
1151
|
// fill of cell to the right
|
|
1152
1152
|
|
|
1153
|
-
color =
|
|
1153
|
+
color = ResolveThemeColor(this.theme, numpad[6].fill);
|
|
1154
1154
|
if (color) {
|
|
1155
1155
|
context.fillStyle = color;
|
|
1156
1156
|
context.fillRect(left + width - 1, top - 1, 1, height + 1);
|
|
@@ -1159,7 +1159,7 @@ export class TileRenderer {
|
|
|
1159
1159
|
|
|
1160
1160
|
// fill of cell underneath
|
|
1161
1161
|
|
|
1162
|
-
color =
|
|
1162
|
+
color = ResolveThemeColor(this.theme, numpad[2].fill);
|
|
1163
1163
|
if (color) {
|
|
1164
1164
|
context.fillStyle = color;
|
|
1165
1165
|
context.fillRect(left - 1, top + height - 1, width + 1, 1);
|
|
@@ -1168,54 +1168,54 @@ export class TileRenderer {
|
|
|
1168
1168
|
// --- corner borders ------------------------------------------------------
|
|
1169
1169
|
|
|
1170
1170
|
if (numpad[6].border_top && !numpad[6].border_left) {
|
|
1171
|
-
context.fillStyle =
|
|
1171
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[6].border_top_fill, 1);
|
|
1172
1172
|
context.fillRect(left + width - 1, top - 2 + numpad[6].border_top, 1, 1);
|
|
1173
1173
|
}
|
|
1174
1174
|
if (numpad[9].border_left) {
|
|
1175
|
-
context.fillStyle =
|
|
1175
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[9].border_left_fill, 1);
|
|
1176
1176
|
context.fillRect(left + width - 1, top - 1, 1, 1);
|
|
1177
1177
|
}
|
|
1178
1178
|
if (numpad[9].border_bottom) {
|
|
1179
|
-
context.fillStyle =
|
|
1179
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[9].border_bottom_fill, 1);
|
|
1180
1180
|
context.fillRect(left + width - 1, top - 2 + numpad[9].border_bottom, 1, 1);
|
|
1181
1181
|
}
|
|
1182
1182
|
|
|
1183
1183
|
if (numpad[4].border_top && !numpad[4].border_right) {
|
|
1184
|
-
context.fillStyle =
|
|
1184
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[4].border_right_fill, 1);
|
|
1185
1185
|
context.fillRect(left - 1, top - 2 + numpad[4].border_top, 1, 1);
|
|
1186
1186
|
}
|
|
1187
1187
|
if (numpad[7].border_right) {
|
|
1188
|
-
context.fillStyle =
|
|
1188
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[7].border_right_fill, 1);
|
|
1189
1189
|
context.fillRect(left - 1, top - 1, 1, 1);
|
|
1190
1190
|
}
|
|
1191
1191
|
if (numpad[7].border_bottom) {
|
|
1192
|
-
context.fillStyle =
|
|
1192
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[7].border_bottom_fill, 1);
|
|
1193
1193
|
context.fillRect(left - 1, top - 2 + numpad[7].border_bottom, 1, 1);
|
|
1194
1194
|
}
|
|
1195
1195
|
|
|
1196
1196
|
if (numpad[6].border_bottom && !numpad[6].border_left) {
|
|
1197
|
-
context.fillStyle =
|
|
1197
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[6].border_bottom_fill, 1);
|
|
1198
1198
|
context.fillRect(left + width - 1, top + height - numpad[6].border_bottom, 1, 1);
|
|
1199
1199
|
}
|
|
1200
1200
|
if (numpad[3].border_left) {
|
|
1201
|
-
context.fillStyle =
|
|
1201
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[3].border_left_fill, 1);
|
|
1202
1202
|
context.fillRect(left + width - 1, top + height - 1, 1, 1);
|
|
1203
1203
|
}
|
|
1204
1204
|
if (numpad[3].border_top) {
|
|
1205
|
-
context.fillStyle =
|
|
1205
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[3].border_top_fill, 1);
|
|
1206
1206
|
context.fillRect(left + width - 1, top + height - numpad[3].border_top, 1, 1);
|
|
1207
1207
|
}
|
|
1208
1208
|
|
|
1209
1209
|
if (numpad[4].border_bottom && !numpad[4].border_right) {
|
|
1210
|
-
context.fillStyle =
|
|
1210
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[4].border_bottom_fill, 1);
|
|
1211
1211
|
context.fillRect(left - 1, top + height - numpad[4].border_bottom, 1, 1);
|
|
1212
1212
|
}
|
|
1213
1213
|
if (numpad[1].border_right) {
|
|
1214
|
-
context.fillStyle =
|
|
1214
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[1].border_right_fill, 1);
|
|
1215
1215
|
context.fillRect(left - 1, top + height - 1, 1, 1);
|
|
1216
1216
|
}
|
|
1217
1217
|
if (numpad[1].border_top) {
|
|
1218
|
-
context.fillStyle =
|
|
1218
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[1].border_top_fill, 1);
|
|
1219
1219
|
context.fillRect(left - 1, top + height - numpad[1].border_top, 1, 1);
|
|
1220
1220
|
}
|
|
1221
1221
|
|
|
@@ -1224,12 +1224,12 @@ export class TileRenderer {
|
|
|
1224
1224
|
// paint top border
|
|
1225
1225
|
|
|
1226
1226
|
if (numpad[8].border_bottom) {
|
|
1227
|
-
context.fillStyle =
|
|
1227
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[8].border_bottom_fill, 1);
|
|
1228
1228
|
if (numpad[8].border_bottom === 2) {
|
|
1229
1229
|
context.fillRect(left - 1, top - 2, width + 1, 1);
|
|
1230
1230
|
context.fillRect(left - 1, top - 0, width + 1, 1);
|
|
1231
|
-
context.fillStyle =
|
|
1232
|
-
||
|
|
1231
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[8].fill)
|
|
1232
|
+
|| ResolveThemeColor(this.theme, this.theme.grid_cell?.fill, 0) || '#fff';
|
|
1233
1233
|
context.fillRect(left - 1, top - 1, width + 1, 1);
|
|
1234
1234
|
}
|
|
1235
1235
|
else {
|
|
@@ -1240,26 +1240,26 @@ export class TileRenderer {
|
|
|
1240
1240
|
// paint left border
|
|
1241
1241
|
|
|
1242
1242
|
if (numpad[4].border_right) {
|
|
1243
|
-
context.fillStyle =
|
|
1243
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[4].border_right_fill, 1);
|
|
1244
1244
|
context.fillRect(left - 1, top - 1, 1, height + 1);
|
|
1245
1245
|
}
|
|
1246
1246
|
|
|
1247
1247
|
// paint right border?
|
|
1248
1248
|
|
|
1249
1249
|
if (numpad[6].border_left) {
|
|
1250
|
-
context.fillStyle =
|
|
1250
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[6].border_left_fill, 1);
|
|
1251
1251
|
context.fillRect(left + width - 1, top - 1, 1, height + 1);
|
|
1252
1252
|
}
|
|
1253
1253
|
|
|
1254
1254
|
// bottom? (...)
|
|
1255
1255
|
|
|
1256
1256
|
if (numpad[2].border_top) {
|
|
1257
|
-
context.fillStyle =
|
|
1257
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[2].border_top_fill, 1);
|
|
1258
1258
|
if (numpad[2].border_top === 2) {
|
|
1259
1259
|
context.fillRect(left - 1, top + height - 2, width + 1, 1);
|
|
1260
1260
|
context.fillRect(left - 1, top + height - 0, width + 1, 1);
|
|
1261
|
-
context.fillStyle =
|
|
1262
|
-
||
|
|
1261
|
+
context.fillStyle = ResolveThemeColor(this.theme, numpad[2].fill)
|
|
1262
|
+
|| ResolveThemeColor(this.theme, this.theme.grid_cell?.fill, 0) || '#fff';
|
|
1263
1263
|
context.fillRect(left - 1, top + height - 1, width + 1, 1);
|
|
1264
1264
|
}
|
|
1265
1265
|
else {
|
|
@@ -1270,12 +1270,12 @@ export class TileRenderer {
|
|
|
1270
1270
|
// -- our borders ----------------------------------------------------------
|
|
1271
1271
|
|
|
1272
1272
|
if (style.border_top) {
|
|
1273
|
-
context.fillStyle =
|
|
1273
|
+
context.fillStyle = ResolveThemeColor(this.theme, style.border_top_fill, 1);
|
|
1274
1274
|
if (style.border_top === 2) {
|
|
1275
1275
|
context.fillRect(left - 1, top - 2, width + 1, 1);
|
|
1276
1276
|
context.fillRect(left - 1, top + 0, width + 1, 1);
|
|
1277
|
-
context.fillStyle =
|
|
1278
|
-
||
|
|
1277
|
+
context.fillStyle = ResolveThemeColor(this.theme, style.fill)
|
|
1278
|
+
|| ResolveThemeColor(this.theme, this.theme.grid_cell?.fill, 0) || '#fff';
|
|
1279
1279
|
context.fillRect(left - 1, top - 1, width + 1, 1);
|
|
1280
1280
|
}
|
|
1281
1281
|
else {
|
|
@@ -1284,22 +1284,22 @@ export class TileRenderer {
|
|
|
1284
1284
|
}
|
|
1285
1285
|
|
|
1286
1286
|
if (style.border_left) {
|
|
1287
|
-
context.fillStyle =
|
|
1287
|
+
context.fillStyle = ResolveThemeColor(this.theme, style.border_left_fill, 1);
|
|
1288
1288
|
context.fillRect(left - 1, top - 1, 1, height + 1);
|
|
1289
1289
|
}
|
|
1290
1290
|
|
|
1291
1291
|
if (style.border_right) {
|
|
1292
|
-
context.fillStyle =
|
|
1292
|
+
context.fillStyle = ResolveThemeColor(this.theme, style.border_right_fill, 1);
|
|
1293
1293
|
context.fillRect(left + width - 1, top - 1, 1, height + 1);
|
|
1294
1294
|
}
|
|
1295
1295
|
|
|
1296
1296
|
if (style.border_bottom) {
|
|
1297
|
-
context.fillStyle =
|
|
1297
|
+
context.fillStyle = ResolveThemeColor(this.theme, style.border_bottom_fill, 1);
|
|
1298
1298
|
if (style.border_bottom === 2) {
|
|
1299
1299
|
context.fillRect(left - 1, top + height - 2, width + 1, 1);
|
|
1300
1300
|
context.fillRect(left - 1, top + height + 0, width + 1, 1);
|
|
1301
|
-
context.fillStyle =
|
|
1302
|
-
||
|
|
1301
|
+
context.fillStyle = ResolveThemeColor(this.theme, style.fill)
|
|
1302
|
+
|| ResolveThemeColor(this.theme, this.theme.grid_cell?.fill, 0) || '#fff';
|
|
1303
1303
|
context.fillRect(left - 1, top + height - 1, width + 1, 1);
|
|
1304
1304
|
}
|
|
1305
1305
|
else {
|
|
@@ -1412,14 +1412,14 @@ export class TileRenderer {
|
|
|
1412
1412
|
}
|
|
1413
1413
|
else {
|
|
1414
1414
|
|
|
1415
|
-
const fill =
|
|
1415
|
+
const fill = ResolveThemeColor(this.theme, style.fill);
|
|
1416
1416
|
|
|
1417
1417
|
if (fill) {
|
|
1418
1418
|
context.fillStyle = fill;
|
|
1419
1419
|
context.fillRect(0, 0, width - 1, height - 1);
|
|
1420
1420
|
}
|
|
1421
1421
|
else {
|
|
1422
|
-
context.fillStyle =
|
|
1422
|
+
context.fillStyle = ResolveThemeColor(this.theme, this.theme.grid_cell?.fill, 0) || '#fff';
|
|
1423
1423
|
context.fillRect(0, 0, width - 1, height - 1);
|
|
1424
1424
|
}
|
|
1425
1425
|
|
|
@@ -1578,7 +1578,7 @@ export class TileRenderer {
|
|
|
1578
1578
|
width,
|
|
1579
1579
|
height);
|
|
1580
1580
|
|
|
1581
|
-
context.strokeStyle = context.fillStyle =
|
|
1581
|
+
context.strokeStyle = context.fillStyle = ResolveThemeColor(this.theme, style.text, 1);
|
|
1582
1582
|
|
|
1583
1583
|
// there's an issue with theme colors, the function may not be able
|
|
1584
1584
|
// to translate so we need to update the style (using a copy) to
|
|
@@ -1871,10 +1871,11 @@ export class TileRenderer {
|
|
|
1871
1871
|
for (const element of overflow_backgrounds) {
|
|
1872
1872
|
|
|
1873
1873
|
if ( element.cell.style?.fill &&
|
|
1874
|
-
|
|
1874
|
+
IsDefinedColor(element.cell.style.fill) &&
|
|
1875
|
+
// (element.cell.style.fill.text || element.cell.style.fill.theme || element.cell.style.fill.theme === 0) &&
|
|
1875
1876
|
!this.options.grid_over_background) {
|
|
1876
1877
|
|
|
1877
|
-
context.fillStyle =
|
|
1878
|
+
context.fillStyle = ResolveThemeColor(this.theme, element.cell.style.fill, 0);
|
|
1878
1879
|
context.fillRect(element.grid.left, element.grid.top, element.grid.width, element.grid.height);
|
|
1879
1880
|
}
|
|
1880
1881
|
else {
|
|
@@ -1894,7 +1895,7 @@ export class TileRenderer {
|
|
|
1894
1895
|
0 );
|
|
1895
1896
|
}
|
|
1896
1897
|
else {
|
|
1897
|
-
context.fillStyle = this.theme.grid_cell?.fill ?
|
|
1898
|
+
context.fillStyle = this.theme.grid_cell?.fill ? ResolveThemeColor(this.theme, this.theme.grid_cell.fill, 0) : '';
|
|
1898
1899
|
context.fillRect(element.background.left, element.background.top,
|
|
1899
1900
|
element.background.width, element.background.height);
|
|
1900
1901
|
}
|
|
@@ -1924,7 +1925,7 @@ export class TileRenderer {
|
|
|
1924
1925
|
context.lineWidth = 1;
|
|
1925
1926
|
|
|
1926
1927
|
context.strokeStyle = context.fillStyle =
|
|
1927
|
-
text_data.format ? text_data.format :
|
|
1928
|
+
text_data.format ? text_data.format : ResolveThemeColor(this.theme, style.text, 1);
|
|
1928
1929
|
|
|
1929
1930
|
context.beginPath();
|
|
1930
1931
|
|
|
@@ -40,15 +40,15 @@ import {
|
|
|
40
40
|
ValueType,
|
|
41
41
|
Localization,
|
|
42
42
|
IsCellAddress,
|
|
43
|
-
ValidationType,
|
|
44
43
|
LoadThemeProperties,
|
|
45
44
|
DefaultTheme,
|
|
46
45
|
ComplexToString,
|
|
47
46
|
IsComplex,
|
|
48
47
|
TextPartFlag,
|
|
48
|
+
IsArea,
|
|
49
49
|
} from 'treb-base-types';
|
|
50
50
|
|
|
51
|
-
import type { ExpressionUnit } from 'treb-parser';
|
|
51
|
+
import type { ExpressionUnit, UnitAddress } from 'treb-parser';
|
|
52
52
|
import {
|
|
53
53
|
DecimalMarkType,
|
|
54
54
|
ArgumentSeparatorType,
|
|
@@ -1465,20 +1465,22 @@ export class Grid extends GridBase {
|
|
|
1465
1465
|
* and will render as a dropdown; the list can be a list of values or
|
|
1466
1466
|
* a range reference.
|
|
1467
1467
|
*/
|
|
1468
|
-
public SetValidation(target?:
|
|
1468
|
+
public SetValidation(target?: IArea, data?: CellValue[]|IArea, error?: boolean): void {
|
|
1469
1469
|
|
|
1470
1470
|
if (!target) {
|
|
1471
1471
|
if (this.primary_selection.empty) {
|
|
1472
1472
|
throw new Error('invalid target in set validation');
|
|
1473
1473
|
}
|
|
1474
|
-
target = this.primary_selection.
|
|
1474
|
+
target = this.primary_selection.area;
|
|
1475
1475
|
}
|
|
1476
1476
|
|
|
1477
|
+
const area = new Area(target.start, target.end);
|
|
1478
|
+
|
|
1477
1479
|
// console.info({target, data});
|
|
1478
1480
|
|
|
1479
1481
|
const command: DataValidationCommand = {
|
|
1480
1482
|
key: CommandKey.DataValidation,
|
|
1481
|
-
area:
|
|
1483
|
+
area: { start: area.start, end: area.end },
|
|
1482
1484
|
error,
|
|
1483
1485
|
};
|
|
1484
1486
|
|
|
@@ -1502,9 +1504,11 @@ export class Grid extends GridBase {
|
|
|
1502
1504
|
//
|
|
1503
1505
|
|
|
1504
1506
|
if (!this.primary_selection.empty &&
|
|
1505
|
-
(!target.sheet_id || target.sheet_id === this.active_sheet.id) &&
|
|
1506
|
-
(this.primary_selection.target
|
|
1507
|
-
|
|
1507
|
+
(!target.start.sheet_id || target.start.sheet_id === this.active_sheet.id) &&
|
|
1508
|
+
area.Contains(this.primary_selection.target)) {
|
|
1509
|
+
|
|
1510
|
+
// (this.primary_selection.target.row === target.start.row) &&
|
|
1511
|
+
// (this.primary_selection.target.column === target.start.column)) {
|
|
1508
1512
|
|
|
1509
1513
|
// console.info('repaint selection');
|
|
1510
1514
|
|
|
@@ -1743,16 +1747,80 @@ export class Grid extends GridBase {
|
|
|
1743
1747
|
|
|
1744
1748
|
}
|
|
1745
1749
|
|
|
1750
|
+
/**
|
|
1751
|
+
* render the given data as R1C1. the source address is a base for
|
|
1752
|
+
* rendering relative addresses (is there a case for this method
|
|
1753
|
+
* handling absolute offsets as well? ...)
|
|
1754
|
+
*
|
|
1755
|
+
* NOTE: this method modifies the input data (at least it does if
|
|
1756
|
+
* it's an array). so this method should only be called with scratchpad
|
|
1757
|
+
* data.
|
|
1758
|
+
*
|
|
1759
|
+
*/
|
|
1760
|
+
public FormatR1C1(data: CellValue|CellValue[][], source: ICellAddress|IArea) {
|
|
1761
|
+
|
|
1762
|
+
// normalize
|
|
1763
|
+
|
|
1764
|
+
if (IsArea(source)) {
|
|
1765
|
+
source = source.start;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
if (!Array.isArray(data)) {
|
|
1769
|
+
data = [[data]];
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
const base: UnitAddress = {
|
|
1773
|
+
type: 'address',
|
|
1774
|
+
label: '',
|
|
1775
|
+
row: source.row,
|
|
1776
|
+
column: source.column,
|
|
1777
|
+
sheet: source.sheet_id ? this.model.sheets.Name(source.sheet_id) : this.active_sheet.name,
|
|
1778
|
+
position: 0,
|
|
1779
|
+
id: 0,
|
|
1780
|
+
};
|
|
1781
|
+
|
|
1782
|
+
for (let r = 0; r < data.length; r++) {
|
|
1783
|
+
const row = data[r];
|
|
1784
|
+
for (let c = 0; c < row.length; c++) {
|
|
1785
|
+
const cell = row[c];
|
|
1786
|
+
if (typeof cell === 'string' && cell[0] === '=') {
|
|
1787
|
+
|
|
1788
|
+
const parse_result = this.parser.Parse(cell);
|
|
1789
|
+
if (parse_result.expression) {
|
|
1790
|
+
row[c] = '=' + this.parser.Render(parse_result.expression, {
|
|
1791
|
+
missing: '',
|
|
1792
|
+
r1c1: true,
|
|
1793
|
+
r1c1_base: {
|
|
1794
|
+
...base,
|
|
1795
|
+
row: source.row + r,
|
|
1796
|
+
column: source.column + c,
|
|
1797
|
+
},
|
|
1798
|
+
});
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
return data;
|
|
1805
|
+
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1746
1808
|
/**
|
|
1747
1809
|
* get data in a given range, optionally formulas
|
|
1748
1810
|
* API method
|
|
1749
1811
|
*/
|
|
1750
|
-
public GetRange(range: ICellAddress | IArea, type?: '
|
|
1812
|
+
public GetRange(range: ICellAddress | IArea, type?: 'formatted'|'A1'|'R1C1'): CellValue|CellValue[][]|undefined {
|
|
1751
1813
|
|
|
1752
1814
|
if (IsCellAddress(range)) {
|
|
1753
1815
|
const sheet = this.model.sheets.Find(range.sheet_id || this.active_sheet.id);
|
|
1754
1816
|
if (sheet) {
|
|
1755
|
-
if (type === '
|
|
1817
|
+
if (type === 'A1' || type === 'R1C1') {
|
|
1818
|
+
const data = sheet.cells.RawValue(range);
|
|
1819
|
+
if (type === 'R1C1') {
|
|
1820
|
+
return this.FormatR1C1(data, range);
|
|
1821
|
+
}
|
|
1822
|
+
return data;
|
|
1823
|
+
}
|
|
1756
1824
|
if (type === 'formatted') { return sheet.GetFormattedRange(range); }
|
|
1757
1825
|
return sheet.cells.GetRange(range);
|
|
1758
1826
|
}
|
|
@@ -1761,7 +1829,13 @@ export class Grid extends GridBase {
|
|
|
1761
1829
|
|
|
1762
1830
|
const sheet = this.model.sheets.Find(range.start.sheet_id || this.active_sheet.id);
|
|
1763
1831
|
if (sheet) {
|
|
1764
|
-
if (type === '
|
|
1832
|
+
if (type === 'A1' || type === 'R1C1') {
|
|
1833
|
+
const data = sheet.cells.RawValue(range.start, range.end);
|
|
1834
|
+
if (type === 'R1C1') {
|
|
1835
|
+
return this.FormatR1C1(data, range);
|
|
1836
|
+
}
|
|
1837
|
+
return data;
|
|
1838
|
+
}
|
|
1765
1839
|
if (type === 'formatted') { return sheet.GetFormattedRange(range.start, range.end); }
|
|
1766
1840
|
return sheet.cells.GetRange(range.start, range.end);
|
|
1767
1841
|
}
|
|
@@ -1886,6 +1960,9 @@ export class Grid extends GridBase {
|
|
|
1886
1960
|
|
|
1887
1961
|
if (!Is2DArray(data)) {
|
|
1888
1962
|
|
|
1963
|
+
// we don't allow this anymore (at least we say we don't)
|
|
1964
|
+
|
|
1965
|
+
|
|
1889
1966
|
// flat array -- we can recycle. recycling is R style (values, not rows).
|
|
1890
1967
|
// in any event convert to [][]
|
|
1891
1968
|
|
|
@@ -1917,6 +1994,56 @@ export class Grid extends GridBase {
|
|
|
1917
1994
|
}
|
|
1918
1995
|
|
|
1919
1996
|
}
|
|
1997
|
+
else {
|
|
1998
|
+
if (recycle) {
|
|
1999
|
+
|
|
2000
|
+
// recycle 2D array. we'll do this if the target range is a multiple
|
|
2001
|
+
// (or larger) of the source array. in blocks.
|
|
2002
|
+
|
|
2003
|
+
if (range.rows > data.length) {
|
|
2004
|
+
const recycle_rows = Math.floor(range.rows / data.length);
|
|
2005
|
+
if (recycle_rows > 1) {
|
|
2006
|
+
const source = [...data];
|
|
2007
|
+
for (let i = 0; i < recycle_rows; i++) {
|
|
2008
|
+
const clone = JSON.parse(JSON.stringify(source));
|
|
2009
|
+
data.push(...clone);
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
let cols = 0;
|
|
2015
|
+
for (const row of data) {
|
|
2016
|
+
cols = Math.max(cols, row.length);
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
if (range.columns > cols) {
|
|
2020
|
+
const recycle_columns = Math.floor(range.columns / cols);
|
|
2021
|
+
if (recycle_columns > 1) {
|
|
2022
|
+
|
|
2023
|
+
for (const row of data) {
|
|
2024
|
+
|
|
2025
|
+
// pad out all rows first, jic
|
|
2026
|
+
while (row.length < cols) {
|
|
2027
|
+
row.push(undefined);
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
// now recycle
|
|
2031
|
+
const source = [...row];
|
|
2032
|
+
for (let i = 0; i < recycle_columns; i++) {
|
|
2033
|
+
const clone = JSON.parse(JSON.stringify(source));
|
|
2034
|
+
row.push(...clone);
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
// ...
|
|
2040
|
+
|
|
2041
|
+
// console.info({recycle_columns});
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
1920
2047
|
|
|
1921
2048
|
if (transpose) { data = this.Transpose(data); }
|
|
1922
2049
|
|
|
@@ -2221,12 +2348,13 @@ export class Grid extends GridBase {
|
|
|
2221
2348
|
// const context = Sheet.measurement_canvas.getContext('2d');
|
|
2222
2349
|
// if (!context) return;
|
|
2223
2350
|
|
|
2224
|
-
let width =
|
|
2225
|
-
const padding = 4 * 2; // FIXME: parameterize
|
|
2351
|
+
let width = 0;
|
|
2352
|
+
const padding = 12; // 4 * 2; // FIXME: parameterize
|
|
2226
2353
|
|
|
2227
2354
|
if (!allow_shrink) width = sheet.GetColumnWidth(column);
|
|
2228
2355
|
|
|
2229
2356
|
for (let row = 0; row < sheet.cells.rows; row++) {
|
|
2357
|
+
|
|
2230
2358
|
const cell = sheet.CellData({ row, column });
|
|
2231
2359
|
let text = cell.formatted || '';
|
|
2232
2360
|
if (typeof text !== 'string') {
|
|
@@ -2243,7 +2371,9 @@ export class Grid extends GridBase {
|
|
|
2243
2371
|
}
|
|
2244
2372
|
}
|
|
2245
2373
|
|
|
2246
|
-
|
|
2374
|
+
if (width > padding + 2) {
|
|
2375
|
+
sheet.SetColumnWidth(column, width);
|
|
2376
|
+
}
|
|
2247
2377
|
|
|
2248
2378
|
}
|
|
2249
2379
|
|
|
@@ -4966,15 +5096,19 @@ export class Grid extends GridBase {
|
|
|
4966
5096
|
|
|
4967
5097
|
}
|
|
4968
5098
|
|
|
4969
|
-
|
|
5099
|
+
const validation = this.active_sheet.GetValidation(target)[0];
|
|
5100
|
+
|
|
5101
|
+
// only consider the first result
|
|
5102
|
+
|
|
5103
|
+
if (validation && validation.error) {
|
|
4970
5104
|
|
|
4971
5105
|
let list: CellValue[]|undefined;
|
|
4972
5106
|
|
|
4973
|
-
if (
|
|
4974
|
-
list =
|
|
5107
|
+
if (validation.type === 'list') {
|
|
5108
|
+
list = validation.list;
|
|
4975
5109
|
}
|
|
4976
|
-
else if (
|
|
4977
|
-
list = this.GetValidationRange(
|
|
5110
|
+
else if (validation.type === 'range') {
|
|
5111
|
+
list = this.GetValidationRange(validation.area);
|
|
4978
5112
|
}
|
|
4979
5113
|
|
|
4980
5114
|
if (list && list.length) {
|
|
@@ -6216,15 +6350,19 @@ export class Grid extends GridBase {
|
|
|
6216
6350
|
// sync up, so it would be a separate function but called at the
|
|
6217
6351
|
// same time.
|
|
6218
6352
|
|
|
6219
|
-
|
|
6353
|
+
// less true now that they're maintained separately
|
|
6354
|
+
|
|
6355
|
+
const validation = this.active_sheet.GetValidation(this.primary_selection.target)[0];
|
|
6356
|
+
|
|
6357
|
+
if (validation && !data.style?.locked) {
|
|
6220
6358
|
|
|
6221
6359
|
let list: CellValue[] | undefined;
|
|
6222
6360
|
|
|
6223
|
-
if (
|
|
6224
|
-
list =
|
|
6361
|
+
if (validation.type === 'list') {
|
|
6362
|
+
list = validation.list;
|
|
6225
6363
|
}
|
|
6226
|
-
else if (
|
|
6227
|
-
list = this.GetValidationRange(
|
|
6364
|
+
else if (validation.type === 'range') {
|
|
6365
|
+
list = this.GetValidationRange(validation.area);
|
|
6228
6366
|
}
|
|
6229
6367
|
|
|
6230
6368
|
if (list && list.length) {
|
|
@@ -6541,7 +6679,7 @@ export class Grid extends GridBase {
|
|
|
6541
6679
|
// tsv_row.push(cell.formatted);
|
|
6542
6680
|
|
|
6543
6681
|
let text_value = '';
|
|
6544
|
-
if (cell.calculated) {
|
|
6682
|
+
if (cell.calculated !== undefined) {
|
|
6545
6683
|
if (cell.calculated_type === ValueType.complex) {
|
|
6546
6684
|
text_value = ComplexToString(cell.calculated as Complex);
|
|
6547
6685
|
}
|
|
@@ -7130,7 +7268,7 @@ export class Grid extends GridBase {
|
|
|
7130
7268
|
|
|
7131
7269
|
if (auto) {
|
|
7132
7270
|
for (const entry of column) {
|
|
7133
|
-
this.AutoSizeColumn(sheet, entry,
|
|
7271
|
+
this.AutoSizeColumn(sheet, entry, true);
|
|
7134
7272
|
}
|
|
7135
7273
|
}
|
|
7136
7274
|
else {
|