@odoo/o-spreadsheet 16.4.0-alpha.1 → 16.4.0-alpha.3
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/o-spreadsheet.cjs.js +638 -466
- package/dist/o-spreadsheet.d.ts +57 -35
- package/dist/o-spreadsheet.esm.js +637 -467
- package/dist/o-spreadsheet.iife.js +638 -466
- package/dist/o-spreadsheet.iife.min.js +249 -245
- package/package.json +1 -1
|
@@ -2214,249 +2214,6 @@ function splitReference(ref) {
|
|
|
2214
2214
|
return { sheetName, xc };
|
|
2215
2215
|
}
|
|
2216
2216
|
|
|
2217
|
-
class RangeImpl {
|
|
2218
|
-
getSheetSize;
|
|
2219
|
-
_zone;
|
|
2220
|
-
parts;
|
|
2221
|
-
invalidXc;
|
|
2222
|
-
prefixSheet = false;
|
|
2223
|
-
sheetId; // the sheet on which the range is defined
|
|
2224
|
-
invalidSheetName; // the name of any sheet that is invalid
|
|
2225
|
-
constructor(args, getSheetSize) {
|
|
2226
|
-
this.getSheetSize = getSheetSize;
|
|
2227
|
-
this._zone = args.zone;
|
|
2228
|
-
this.parts = args.parts;
|
|
2229
|
-
this.prefixSheet = args.prefixSheet;
|
|
2230
|
-
this.invalidXc = args.invalidXc;
|
|
2231
|
-
this.sheetId = args.sheetId;
|
|
2232
|
-
this.invalidSheetName = args.invalidSheetName;
|
|
2233
|
-
}
|
|
2234
|
-
static fromRange(range, getters) {
|
|
2235
|
-
if (range instanceof RangeImpl) {
|
|
2236
|
-
return range;
|
|
2237
|
-
}
|
|
2238
|
-
return new RangeImpl(range, getters.getSheetSize);
|
|
2239
|
-
}
|
|
2240
|
-
get unboundedZone() {
|
|
2241
|
-
return this._zone;
|
|
2242
|
-
}
|
|
2243
|
-
get zone() {
|
|
2244
|
-
const { left, top, bottom, right } = this._zone;
|
|
2245
|
-
if (right !== undefined && bottom !== undefined)
|
|
2246
|
-
return { left, top, right, bottom };
|
|
2247
|
-
else if (bottom === undefined && right !== undefined) {
|
|
2248
|
-
return { right, top, left, bottom: this.getSheetSize(this.sheetId).numberOfRows - 1 };
|
|
2249
|
-
}
|
|
2250
|
-
else if (right === undefined && bottom !== undefined) {
|
|
2251
|
-
return { bottom, left, top, right: this.getSheetSize(this.sheetId).numberOfCols - 1 };
|
|
2252
|
-
}
|
|
2253
|
-
throw new Error(_lt("Bad zone format"));
|
|
2254
|
-
}
|
|
2255
|
-
static getRangeParts(xc, zone) {
|
|
2256
|
-
const parts = xc.split(":").map((p) => {
|
|
2257
|
-
const isFullRow = isRowReference(p);
|
|
2258
|
-
return {
|
|
2259
|
-
colFixed: isFullRow ? false : p.startsWith("$"),
|
|
2260
|
-
rowFixed: isFullRow ? p.startsWith("$") : p.includes("$", 1),
|
|
2261
|
-
};
|
|
2262
|
-
});
|
|
2263
|
-
const isFullCol = zone.bottom === undefined;
|
|
2264
|
-
const isFullRow = zone.right === undefined;
|
|
2265
|
-
if (isFullCol) {
|
|
2266
|
-
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2267
|
-
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2268
|
-
if (zone.left === zone.right) {
|
|
2269
|
-
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2270
|
-
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2271
|
-
}
|
|
2272
|
-
}
|
|
2273
|
-
if (isFullRow) {
|
|
2274
|
-
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2275
|
-
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2276
|
-
if (zone.top === zone.bottom) {
|
|
2277
|
-
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2278
|
-
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2279
|
-
}
|
|
2280
|
-
}
|
|
2281
|
-
return parts;
|
|
2282
|
-
}
|
|
2283
|
-
get isFullCol() {
|
|
2284
|
-
return this._zone.bottom === undefined;
|
|
2285
|
-
}
|
|
2286
|
-
get isFullRow() {
|
|
2287
|
-
return this._zone.right === undefined;
|
|
2288
|
-
}
|
|
2289
|
-
get rangeData() {
|
|
2290
|
-
return {
|
|
2291
|
-
_zone: this._zone,
|
|
2292
|
-
_sheetId: this.sheetId,
|
|
2293
|
-
};
|
|
2294
|
-
}
|
|
2295
|
-
/**
|
|
2296
|
-
* Check that a zone is valid regarding the order of top-bottom and left-right.
|
|
2297
|
-
* Left should be smaller than right, top should be smaller than bottom.
|
|
2298
|
-
* If it's not the case, simply invert them, and invert the linked parts
|
|
2299
|
-
*/
|
|
2300
|
-
orderZone() {
|
|
2301
|
-
const zone = { ...this._zone };
|
|
2302
|
-
let parts = this.parts;
|
|
2303
|
-
if (zone.right !== undefined && zone.right < zone.left) {
|
|
2304
|
-
let right = zone.right;
|
|
2305
|
-
zone.right = zone.left;
|
|
2306
|
-
zone.left = right;
|
|
2307
|
-
parts = [
|
|
2308
|
-
{
|
|
2309
|
-
colFixed: parts[1]?.colFixed || false,
|
|
2310
|
-
rowFixed: parts[0]?.rowFixed || false,
|
|
2311
|
-
},
|
|
2312
|
-
{
|
|
2313
|
-
colFixed: parts[0]?.colFixed || false,
|
|
2314
|
-
rowFixed: parts[1]?.rowFixed || false,
|
|
2315
|
-
},
|
|
2316
|
-
];
|
|
2317
|
-
}
|
|
2318
|
-
if (zone.bottom !== undefined && zone.bottom < zone.top) {
|
|
2319
|
-
let bottom = zone.bottom;
|
|
2320
|
-
zone.bottom = zone.top;
|
|
2321
|
-
zone.top = bottom;
|
|
2322
|
-
parts = [
|
|
2323
|
-
{
|
|
2324
|
-
colFixed: parts[0]?.colFixed || false,
|
|
2325
|
-
rowFixed: parts[1]?.rowFixed || false,
|
|
2326
|
-
},
|
|
2327
|
-
{
|
|
2328
|
-
colFixed: parts[1]?.colFixed || false,
|
|
2329
|
-
rowFixed: parts[0]?.rowFixed || false,
|
|
2330
|
-
},
|
|
2331
|
-
];
|
|
2332
|
-
}
|
|
2333
|
-
return this.clone({ zone, parts });
|
|
2334
|
-
}
|
|
2335
|
-
/**
|
|
2336
|
-
*
|
|
2337
|
-
* @param rangeParams optional, values to put in the cloned range instead of the current values of the range
|
|
2338
|
-
*/
|
|
2339
|
-
clone(rangeParams) {
|
|
2340
|
-
return new RangeImpl({
|
|
2341
|
-
zone: rangeParams?.zone ? rangeParams.zone : { ...this._zone },
|
|
2342
|
-
sheetId: rangeParams?.sheetId ? rangeParams.sheetId : this.sheetId,
|
|
2343
|
-
invalidSheetName: rangeParams && "invalidSheetName" in rangeParams // 'attr in obj' instead of just 'obj.attr' because we accept undefined values
|
|
2344
|
-
? rangeParams.invalidSheetName
|
|
2345
|
-
: this.invalidSheetName,
|
|
2346
|
-
invalidXc: rangeParams && "invalidXc" in rangeParams ? rangeParams.invalidXc : this.invalidXc,
|
|
2347
|
-
parts: rangeParams?.parts
|
|
2348
|
-
? rangeParams.parts
|
|
2349
|
-
: this.parts.map((part) => {
|
|
2350
|
-
return { rowFixed: part.rowFixed, colFixed: part.colFixed };
|
|
2351
|
-
}),
|
|
2352
|
-
prefixSheet: rangeParams?.prefixSheet ? rangeParams.prefixSheet : this.prefixSheet,
|
|
2353
|
-
}, this.getSheetSize);
|
|
2354
|
-
}
|
|
2355
|
-
}
|
|
2356
|
-
/**
|
|
2357
|
-
* Copy a range. If the range is on the sheetIdFrom, the range will target
|
|
2358
|
-
* sheetIdTo.
|
|
2359
|
-
*/
|
|
2360
|
-
function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
|
|
2361
|
-
const sheetId = range.sheetId === sheetIdFrom ? sheetIdTo : range.sheetId;
|
|
2362
|
-
return range.clone({ sheetId });
|
|
2363
|
-
}
|
|
2364
|
-
/**
|
|
2365
|
-
* Create a range from a xc. If the xc is empty, this function returns undefined.
|
|
2366
|
-
*/
|
|
2367
|
-
function createRange(getters, sheetId, range) {
|
|
2368
|
-
return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
|
|
2369
|
-
}
|
|
2370
|
-
|
|
2371
|
-
/** Methods from Odoo Web Utils */
|
|
2372
|
-
/**
|
|
2373
|
-
* This function computes a score that represent the fact that the
|
|
2374
|
-
* string contains the pattern, or not
|
|
2375
|
-
*
|
|
2376
|
-
* - If the score is 0, the string does not contain the letters of the pattern in
|
|
2377
|
-
* the correct order.
|
|
2378
|
-
* - if the score is > 0, it actually contains the letters.
|
|
2379
|
-
*
|
|
2380
|
-
* Better matches will get a higher score: consecutive letters are better,
|
|
2381
|
-
* and a match closer to the beginning of the string is also scored higher.
|
|
2382
|
-
*/
|
|
2383
|
-
function fuzzyMatch(pattern, str) {
|
|
2384
|
-
pattern = pattern.toLocaleLowerCase();
|
|
2385
|
-
str = str.toLocaleLowerCase();
|
|
2386
|
-
let totalScore = 0;
|
|
2387
|
-
let currentScore = 0;
|
|
2388
|
-
let len = str.length;
|
|
2389
|
-
let patternIndex = 0;
|
|
2390
|
-
for (let i = 0; i < len; i++) {
|
|
2391
|
-
if (str[i] === pattern[patternIndex]) {
|
|
2392
|
-
patternIndex++;
|
|
2393
|
-
currentScore += 100 + currentScore - i / 200;
|
|
2394
|
-
}
|
|
2395
|
-
else {
|
|
2396
|
-
currentScore = 0;
|
|
2397
|
-
}
|
|
2398
|
-
totalScore = totalScore + currentScore;
|
|
2399
|
-
}
|
|
2400
|
-
return patternIndex === pattern.length ? totalScore : 0;
|
|
2401
|
-
}
|
|
2402
|
-
/**
|
|
2403
|
-
* Return a list of things that matches a pattern, ordered by their 'score' (
|
|
2404
|
-
* higher score first). An higher score means that the match is better. For
|
|
2405
|
-
* example, consecutive letters are considered a better match.
|
|
2406
|
-
*/
|
|
2407
|
-
function fuzzyLookup(pattern, list, fn) {
|
|
2408
|
-
const results = [];
|
|
2409
|
-
list.forEach((data) => {
|
|
2410
|
-
const score = fuzzyMatch(pattern, fn(data));
|
|
2411
|
-
if (score > 0) {
|
|
2412
|
-
results.push({ score, elem: data });
|
|
2413
|
-
}
|
|
2414
|
-
});
|
|
2415
|
-
// we want better matches first
|
|
2416
|
-
results.sort((a, b) => b.score - a.score);
|
|
2417
|
-
return results.map((r) => r.elem);
|
|
2418
|
-
}
|
|
2419
|
-
|
|
2420
|
-
function createDefaultRows(rowNumber) {
|
|
2421
|
-
const rows = [];
|
|
2422
|
-
for (let i = 0; i < rowNumber; i++) {
|
|
2423
|
-
const row = {
|
|
2424
|
-
cells: {},
|
|
2425
|
-
};
|
|
2426
|
-
rows.push(row);
|
|
2427
|
-
}
|
|
2428
|
-
return rows;
|
|
2429
|
-
}
|
|
2430
|
-
|
|
2431
|
-
/*
|
|
2432
|
-
* https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
|
|
2433
|
-
* */
|
|
2434
|
-
class UuidGenerator {
|
|
2435
|
-
isFastIdStrategy = false;
|
|
2436
|
-
fastIdStart = 0;
|
|
2437
|
-
setIsFastStrategy(isFast) {
|
|
2438
|
-
this.isFastIdStrategy = isFast;
|
|
2439
|
-
}
|
|
2440
|
-
uuidv4() {
|
|
2441
|
-
if (this.isFastIdStrategy) {
|
|
2442
|
-
this.fastIdStart++;
|
|
2443
|
-
return String(this.fastIdStart);
|
|
2444
|
-
//@ts-ignore
|
|
2445
|
-
}
|
|
2446
|
-
else if (window.crypto && window.crypto.getRandomValues) {
|
|
2447
|
-
//@ts-ignore
|
|
2448
|
-
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16));
|
|
2449
|
-
}
|
|
2450
|
-
else {
|
|
2451
|
-
// mainly for jest and other browsers that do not have the crypto functionality
|
|
2452
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
2453
|
-
var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
|
|
2454
|
-
return v.toString(16);
|
|
2455
|
-
});
|
|
2456
|
-
}
|
|
2457
|
-
}
|
|
2458
|
-
}
|
|
2459
|
-
|
|
2460
2217
|
/**
|
|
2461
2218
|
* Convert from a cartesian reference to a Zone
|
|
2462
2219
|
* The range boundaries will be kept in the same order as the
|
|
@@ -3063,6 +2820,287 @@ function getZonesRows(zones) {
|
|
|
3063
2820
|
return set;
|
|
3064
2821
|
}
|
|
3065
2822
|
|
|
2823
|
+
class RangeImpl {
|
|
2824
|
+
getSheetSize;
|
|
2825
|
+
_zone;
|
|
2826
|
+
parts;
|
|
2827
|
+
invalidXc;
|
|
2828
|
+
prefixSheet = false;
|
|
2829
|
+
sheetId; // the sheet on which the range is defined
|
|
2830
|
+
invalidSheetName; // the name of any sheet that is invalid
|
|
2831
|
+
constructor(args, getSheetSize) {
|
|
2832
|
+
this.getSheetSize = getSheetSize;
|
|
2833
|
+
this._zone = args.zone;
|
|
2834
|
+
this.parts = args.parts;
|
|
2835
|
+
this.prefixSheet = args.prefixSheet;
|
|
2836
|
+
this.invalidXc = args.invalidXc;
|
|
2837
|
+
this.sheetId = args.sheetId;
|
|
2838
|
+
this.invalidSheetName = args.invalidSheetName;
|
|
2839
|
+
}
|
|
2840
|
+
static fromRange(range, getters) {
|
|
2841
|
+
if (range instanceof RangeImpl) {
|
|
2842
|
+
return range;
|
|
2843
|
+
}
|
|
2844
|
+
return new RangeImpl(range, getters.getSheetSize);
|
|
2845
|
+
}
|
|
2846
|
+
get unboundedZone() {
|
|
2847
|
+
return this._zone;
|
|
2848
|
+
}
|
|
2849
|
+
get zone() {
|
|
2850
|
+
const { left, top, bottom, right } = this._zone;
|
|
2851
|
+
if (right !== undefined && bottom !== undefined)
|
|
2852
|
+
return { left, top, right, bottom };
|
|
2853
|
+
else if (bottom === undefined && right !== undefined) {
|
|
2854
|
+
return { right, top, left, bottom: this.getSheetSize(this.sheetId).numberOfRows - 1 };
|
|
2855
|
+
}
|
|
2856
|
+
else if (right === undefined && bottom !== undefined) {
|
|
2857
|
+
return { bottom, left, top, right: this.getSheetSize(this.sheetId).numberOfCols - 1 };
|
|
2858
|
+
}
|
|
2859
|
+
throw new Error(_lt("Bad zone format"));
|
|
2860
|
+
}
|
|
2861
|
+
static getRangeParts(xc, zone) {
|
|
2862
|
+
const parts = xc.split(":").map((p) => {
|
|
2863
|
+
const isFullRow = isRowReference(p);
|
|
2864
|
+
return {
|
|
2865
|
+
colFixed: isFullRow ? false : p.startsWith("$"),
|
|
2866
|
+
rowFixed: isFullRow ? p.startsWith("$") : p.includes("$", 1),
|
|
2867
|
+
};
|
|
2868
|
+
});
|
|
2869
|
+
const isFullCol = zone.bottom === undefined;
|
|
2870
|
+
const isFullRow = zone.right === undefined;
|
|
2871
|
+
if (isFullCol) {
|
|
2872
|
+
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2873
|
+
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2874
|
+
if (zone.left === zone.right) {
|
|
2875
|
+
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2876
|
+
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
if (isFullRow) {
|
|
2880
|
+
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2881
|
+
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2882
|
+
if (zone.top === zone.bottom) {
|
|
2883
|
+
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2884
|
+
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
return parts;
|
|
2888
|
+
}
|
|
2889
|
+
get isFullCol() {
|
|
2890
|
+
return this._zone.bottom === undefined;
|
|
2891
|
+
}
|
|
2892
|
+
get isFullRow() {
|
|
2893
|
+
return this._zone.right === undefined;
|
|
2894
|
+
}
|
|
2895
|
+
get rangeData() {
|
|
2896
|
+
return {
|
|
2897
|
+
_zone: this._zone,
|
|
2898
|
+
_sheetId: this.sheetId,
|
|
2899
|
+
};
|
|
2900
|
+
}
|
|
2901
|
+
/**
|
|
2902
|
+
* Check that a zone is valid regarding the order of top-bottom and left-right.
|
|
2903
|
+
* Left should be smaller than right, top should be smaller than bottom.
|
|
2904
|
+
* If it's not the case, simply invert them, and invert the linked parts
|
|
2905
|
+
*/
|
|
2906
|
+
orderZone() {
|
|
2907
|
+
const zone = { ...this._zone };
|
|
2908
|
+
let parts = this.parts;
|
|
2909
|
+
if (zone.right !== undefined && zone.right < zone.left) {
|
|
2910
|
+
let right = zone.right;
|
|
2911
|
+
zone.right = zone.left;
|
|
2912
|
+
zone.left = right;
|
|
2913
|
+
parts = [
|
|
2914
|
+
{
|
|
2915
|
+
colFixed: parts[1]?.colFixed || false,
|
|
2916
|
+
rowFixed: parts[0]?.rowFixed || false,
|
|
2917
|
+
},
|
|
2918
|
+
{
|
|
2919
|
+
colFixed: parts[0]?.colFixed || false,
|
|
2920
|
+
rowFixed: parts[1]?.rowFixed || false,
|
|
2921
|
+
},
|
|
2922
|
+
];
|
|
2923
|
+
}
|
|
2924
|
+
if (zone.bottom !== undefined && zone.bottom < zone.top) {
|
|
2925
|
+
let bottom = zone.bottom;
|
|
2926
|
+
zone.bottom = zone.top;
|
|
2927
|
+
zone.top = bottom;
|
|
2928
|
+
parts = [
|
|
2929
|
+
{
|
|
2930
|
+
colFixed: parts[0]?.colFixed || false,
|
|
2931
|
+
rowFixed: parts[1]?.rowFixed || false,
|
|
2932
|
+
},
|
|
2933
|
+
{
|
|
2934
|
+
colFixed: parts[1]?.colFixed || false,
|
|
2935
|
+
rowFixed: parts[0]?.rowFixed || false,
|
|
2936
|
+
},
|
|
2937
|
+
];
|
|
2938
|
+
}
|
|
2939
|
+
return this.clone({ zone, parts });
|
|
2940
|
+
}
|
|
2941
|
+
/**
|
|
2942
|
+
*
|
|
2943
|
+
* @param rangeParams optional, values to put in the cloned range instead of the current values of the range
|
|
2944
|
+
*/
|
|
2945
|
+
clone(rangeParams) {
|
|
2946
|
+
return new RangeImpl({
|
|
2947
|
+
zone: rangeParams?.zone ? rangeParams.zone : { ...this._zone },
|
|
2948
|
+
sheetId: rangeParams?.sheetId ? rangeParams.sheetId : this.sheetId,
|
|
2949
|
+
invalidSheetName: rangeParams && "invalidSheetName" in rangeParams // 'attr in obj' instead of just 'obj.attr' because we accept undefined values
|
|
2950
|
+
? rangeParams.invalidSheetName
|
|
2951
|
+
: this.invalidSheetName,
|
|
2952
|
+
invalidXc: rangeParams && "invalidXc" in rangeParams ? rangeParams.invalidXc : this.invalidXc,
|
|
2953
|
+
parts: rangeParams?.parts
|
|
2954
|
+
? rangeParams.parts
|
|
2955
|
+
: this.parts.map((part) => {
|
|
2956
|
+
return { rowFixed: part.rowFixed, colFixed: part.colFixed };
|
|
2957
|
+
}),
|
|
2958
|
+
prefixSheet: rangeParams?.prefixSheet ? rangeParams.prefixSheet : this.prefixSheet,
|
|
2959
|
+
}, this.getSheetSize);
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
/**
|
|
2963
|
+
* Copy a range. If the range is on the sheetIdFrom, the range will target
|
|
2964
|
+
* sheetIdTo.
|
|
2965
|
+
*/
|
|
2966
|
+
function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
|
|
2967
|
+
const sheetId = range.sheetId === sheetIdFrom ? sheetIdTo : range.sheetId;
|
|
2968
|
+
return range.clone({ sheetId });
|
|
2969
|
+
}
|
|
2970
|
+
/**
|
|
2971
|
+
* Create a range from a xc. If the xc is empty, this function returns undefined.
|
|
2972
|
+
*/
|
|
2973
|
+
function createRange(getters, sheetId, range) {
|
|
2974
|
+
return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
|
|
2975
|
+
}
|
|
2976
|
+
/**
|
|
2977
|
+
* Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
|
|
2978
|
+
* For example, A1:B4 will become [A1:A4, B1:B4]
|
|
2979
|
+
*/
|
|
2980
|
+
function spreadRange(ranges) {
|
|
2981
|
+
const postProcessedRanges = [];
|
|
2982
|
+
for (const range of ranges) {
|
|
2983
|
+
const { sheetName } = splitReference(range);
|
|
2984
|
+
const sheetPrefix = sheetName ? `${sheetName}!` : "";
|
|
2985
|
+
const zone = toUnboundedZone(range);
|
|
2986
|
+
if (zone.bottom !== zone.top && zone.left != zone.right) {
|
|
2987
|
+
if (zone.right) {
|
|
2988
|
+
for (let j = zone.left; j <= zone.right; ++j) {
|
|
2989
|
+
postProcessedRanges.push(`${sheetPrefix}${zoneToXc({
|
|
2990
|
+
left: j,
|
|
2991
|
+
right: j,
|
|
2992
|
+
top: zone.top,
|
|
2993
|
+
bottom: zone.bottom,
|
|
2994
|
+
})}`);
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
else {
|
|
2998
|
+
for (let j = zone.top; j <= zone.bottom; ++j) {
|
|
2999
|
+
postProcessedRanges.push(`${sheetPrefix}${zoneToXc({
|
|
3000
|
+
left: zone.left,
|
|
3001
|
+
right: zone.right,
|
|
3002
|
+
top: j,
|
|
3003
|
+
bottom: j,
|
|
3004
|
+
})}`);
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
else {
|
|
3009
|
+
postProcessedRanges.push(range);
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
return postProcessedRanges;
|
|
3013
|
+
}
|
|
3014
|
+
|
|
3015
|
+
/** Methods from Odoo Web Utils */
|
|
3016
|
+
/**
|
|
3017
|
+
* This function computes a score that represent the fact that the
|
|
3018
|
+
* string contains the pattern, or not
|
|
3019
|
+
*
|
|
3020
|
+
* - If the score is 0, the string does not contain the letters of the pattern in
|
|
3021
|
+
* the correct order.
|
|
3022
|
+
* - if the score is > 0, it actually contains the letters.
|
|
3023
|
+
*
|
|
3024
|
+
* Better matches will get a higher score: consecutive letters are better,
|
|
3025
|
+
* and a match closer to the beginning of the string is also scored higher.
|
|
3026
|
+
*/
|
|
3027
|
+
function fuzzyMatch(pattern, str) {
|
|
3028
|
+
pattern = pattern.toLocaleLowerCase();
|
|
3029
|
+
str = str.toLocaleLowerCase();
|
|
3030
|
+
let totalScore = 0;
|
|
3031
|
+
let currentScore = 0;
|
|
3032
|
+
let len = str.length;
|
|
3033
|
+
let patternIndex = 0;
|
|
3034
|
+
for (let i = 0; i < len; i++) {
|
|
3035
|
+
if (str[i] === pattern[patternIndex]) {
|
|
3036
|
+
patternIndex++;
|
|
3037
|
+
currentScore += 100 + currentScore - i / 200;
|
|
3038
|
+
}
|
|
3039
|
+
else {
|
|
3040
|
+
currentScore = 0;
|
|
3041
|
+
}
|
|
3042
|
+
totalScore = totalScore + currentScore;
|
|
3043
|
+
}
|
|
3044
|
+
return patternIndex === pattern.length ? totalScore : 0;
|
|
3045
|
+
}
|
|
3046
|
+
/**
|
|
3047
|
+
* Return a list of things that matches a pattern, ordered by their 'score' (
|
|
3048
|
+
* higher score first). An higher score means that the match is better. For
|
|
3049
|
+
* example, consecutive letters are considered a better match.
|
|
3050
|
+
*/
|
|
3051
|
+
function fuzzyLookup(pattern, list, fn) {
|
|
3052
|
+
const results = [];
|
|
3053
|
+
list.forEach((data) => {
|
|
3054
|
+
const score = fuzzyMatch(pattern, fn(data));
|
|
3055
|
+
if (score > 0) {
|
|
3056
|
+
results.push({ score, elem: data });
|
|
3057
|
+
}
|
|
3058
|
+
});
|
|
3059
|
+
// we want better matches first
|
|
3060
|
+
results.sort((a, b) => b.score - a.score);
|
|
3061
|
+
return results.map((r) => r.elem);
|
|
3062
|
+
}
|
|
3063
|
+
|
|
3064
|
+
function createDefaultRows(rowNumber) {
|
|
3065
|
+
const rows = [];
|
|
3066
|
+
for (let i = 0; i < rowNumber; i++) {
|
|
3067
|
+
const row = {
|
|
3068
|
+
cells: {},
|
|
3069
|
+
};
|
|
3070
|
+
rows.push(row);
|
|
3071
|
+
}
|
|
3072
|
+
return rows;
|
|
3073
|
+
}
|
|
3074
|
+
|
|
3075
|
+
/*
|
|
3076
|
+
* https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
|
|
3077
|
+
* */
|
|
3078
|
+
class UuidGenerator {
|
|
3079
|
+
isFastIdStrategy = false;
|
|
3080
|
+
fastIdStart = 0;
|
|
3081
|
+
setIsFastStrategy(isFast) {
|
|
3082
|
+
this.isFastIdStrategy = isFast;
|
|
3083
|
+
}
|
|
3084
|
+
uuidv4() {
|
|
3085
|
+
if (this.isFastIdStrategy) {
|
|
3086
|
+
this.fastIdStart++;
|
|
3087
|
+
return String(this.fastIdStart);
|
|
3088
|
+
//@ts-ignore
|
|
3089
|
+
}
|
|
3090
|
+
else if (window.crypto && window.crypto.getRandomValues) {
|
|
3091
|
+
//@ts-ignore
|
|
3092
|
+
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16));
|
|
3093
|
+
}
|
|
3094
|
+
else {
|
|
3095
|
+
// mainly for jest and other browsers that do not have the crypto functionality
|
|
3096
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
3097
|
+
var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
|
|
3098
|
+
return v.toString(16);
|
|
3099
|
+
});
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
|
|
3066
3104
|
class ChartJsComponent extends Component {
|
|
3067
3105
|
static template = "o-spreadsheet-ChartJsComponent";
|
|
3068
3106
|
canvas = useRef("graphContainer");
|
|
@@ -5180,14 +5218,6 @@ function* iterateChildren(el) {
|
|
|
5180
5218
|
}
|
|
5181
5219
|
}
|
|
5182
5220
|
}
|
|
5183
|
-
function getElementScrollTop(el) {
|
|
5184
|
-
return el?.scrollTop || 0;
|
|
5185
|
-
}
|
|
5186
|
-
function setElementScrollTop(el, scroll) {
|
|
5187
|
-
if (!el)
|
|
5188
|
-
return;
|
|
5189
|
-
el.scrollTop = scroll;
|
|
5190
|
-
}
|
|
5191
5221
|
function getOpenedMenus() {
|
|
5192
5222
|
return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
|
|
5193
5223
|
}
|
|
@@ -17642,50 +17672,51 @@ const uuidGenerator$1 = new UuidGenerator();
|
|
|
17642
17672
|
css /* scss */ `
|
|
17643
17673
|
.o-selection {
|
|
17644
17674
|
.o-selection-input {
|
|
17645
|
-
|
|
17646
|
-
flex-direction: row;
|
|
17675
|
+
padding: 2px 0px;
|
|
17647
17676
|
|
|
17648
17677
|
input {
|
|
17649
17678
|
padding: 4px 6px;
|
|
17650
17679
|
border-radius: 4px;
|
|
17651
17680
|
box-sizing: border-box;
|
|
17652
|
-
flex-grow: 2;
|
|
17653
17681
|
}
|
|
17654
17682
|
input:focus {
|
|
17655
17683
|
outline: none;
|
|
17656
17684
|
}
|
|
17657
17685
|
input.o-required,
|
|
17658
17686
|
input.o-focused {
|
|
17659
|
-
border
|
|
17660
|
-
padding: 3px 5px;
|
|
17687
|
+
border: 1px solid;
|
|
17661
17688
|
}
|
|
17662
17689
|
input.o-focused {
|
|
17663
|
-
border-
|
|
17690
|
+
border-width: 2px;
|
|
17691
|
+
padding: 3px 5px;
|
|
17664
17692
|
}
|
|
17665
17693
|
input.o-invalid {
|
|
17666
|
-
|
|
17694
|
+
/* The background-color is similar to the bootstrap alert-danger class but, because of the commit 0358a76d,
|
|
17695
|
+
* which avoids being parasitized by the dark-mode in spreadsheet, we cannot use this class.
|
|
17696
|
+
* TODO: Replace with the bootstrap alert-danger class when we support dark mode
|
|
17697
|
+
*/
|
|
17698
|
+
background-color: #ffdddd;
|
|
17699
|
+
border-width: 2px;
|
|
17667
17700
|
}
|
|
17668
17701
|
button.o-btn {
|
|
17669
|
-
background: transparent;
|
|
17670
|
-
border: none;
|
|
17671
17702
|
color: #333;
|
|
17672
|
-
cursor: pointer;
|
|
17673
17703
|
}
|
|
17674
17704
|
button.o-btn-action {
|
|
17675
17705
|
margin: 8px 1px;
|
|
17676
17706
|
border-radius: 4px;
|
|
17677
|
-
background: transparent;
|
|
17678
17707
|
border: 1px solid #dadce0;
|
|
17679
17708
|
color: #188038;
|
|
17680
|
-
font-weight: bold;
|
|
17681
17709
|
font-size: 14px;
|
|
17682
17710
|
height: 25px;
|
|
17683
17711
|
}
|
|
17712
|
+
.error-icon {
|
|
17713
|
+
right: 7px;
|
|
17714
|
+
top: 7px;
|
|
17715
|
+
}
|
|
17684
17716
|
}
|
|
17685
17717
|
/** Make the character a bit bigger
|
|
17686
17718
|
compared to its neighbor INPUT box */
|
|
17687
17719
|
.o-remove-selection {
|
|
17688
|
-
font-weight: bold;
|
|
17689
17720
|
font-size: calc(100% + 4px);
|
|
17690
17721
|
}
|
|
17691
17722
|
}
|
|
@@ -17701,7 +17732,7 @@ css /* scss */ `
|
|
|
17701
17732
|
class SelectionInput extends Component {
|
|
17702
17733
|
static template = "o-spreadsheet-SelectionInput";
|
|
17703
17734
|
id = uuidGenerator$1.uuidv4();
|
|
17704
|
-
previousRanges = this.props.ranges || [];
|
|
17735
|
+
previousRanges = this.props.ranges() || [];
|
|
17705
17736
|
originSheet = this.env.model.getters.getActiveSheetId();
|
|
17706
17737
|
state = useState({
|
|
17707
17738
|
isMissing: false,
|
|
@@ -17709,11 +17740,11 @@ class SelectionInput extends Component {
|
|
|
17709
17740
|
});
|
|
17710
17741
|
focusedInput = useRef("focusedInput");
|
|
17711
17742
|
get ranges() {
|
|
17712
|
-
const
|
|
17713
|
-
const ranges =
|
|
17714
|
-
?
|
|
17715
|
-
: this.props.ranges
|
|
17716
|
-
? this.props.ranges.map((xc, id) => ({
|
|
17743
|
+
const existingSelectionRanges = this.env.model.getters.getSelectionInput(this.id);
|
|
17744
|
+
const ranges = existingSelectionRanges.length
|
|
17745
|
+
? existingSelectionRanges
|
|
17746
|
+
: this.props.ranges()
|
|
17747
|
+
? this.props.ranges().map((xc, id) => ({
|
|
17717
17748
|
xc,
|
|
17718
17749
|
id,
|
|
17719
17750
|
isFocused: false,
|
|
@@ -17733,6 +17764,12 @@ class SelectionInput extends Component {
|
|
|
17733
17764
|
get isInvalid() {
|
|
17734
17765
|
return this.props.isInvalid || this.state.isMissing;
|
|
17735
17766
|
}
|
|
17767
|
+
get isConfirmable() {
|
|
17768
|
+
return this.hasFocus && this.ranges.every((range) => range.isValidRange);
|
|
17769
|
+
}
|
|
17770
|
+
get isResettable() {
|
|
17771
|
+
return this.previousRanges.join() !== this.ranges.map((r) => r.xc).join();
|
|
17772
|
+
}
|
|
17736
17773
|
setup() {
|
|
17737
17774
|
useEffect(() => this.focusedInput.el?.focus(), () => [this.focusedInput.el]);
|
|
17738
17775
|
onMounted(() => this.enableNewSelectionInput());
|
|
@@ -17742,7 +17779,7 @@ class SelectionInput extends Component {
|
|
|
17742
17779
|
enableNewSelectionInput() {
|
|
17743
17780
|
this.env.model.dispatch("ENABLE_NEW_SELECTION_INPUT", {
|
|
17744
17781
|
id: this.id,
|
|
17745
|
-
initialRanges: this.props.ranges,
|
|
17782
|
+
initialRanges: this.props.ranges(),
|
|
17746
17783
|
hasSingleRange: this.props.hasSingleRange,
|
|
17747
17784
|
});
|
|
17748
17785
|
}
|
|
@@ -17751,7 +17788,8 @@ class SelectionInput extends Component {
|
|
|
17751
17788
|
}
|
|
17752
17789
|
checkChange() {
|
|
17753
17790
|
const value = this.env.model.getters.getSelectionInputValue(this.id);
|
|
17754
|
-
|
|
17791
|
+
const valid = !this.isInvalid && this.ranges.every((range) => range.isValidRange);
|
|
17792
|
+
if (valid && this.previousRanges.join() !== value.join()) {
|
|
17755
17793
|
this.triggerChange();
|
|
17756
17794
|
}
|
|
17757
17795
|
}
|
|
@@ -17762,7 +17800,6 @@ class SelectionInput extends Component {
|
|
|
17762
17800
|
triggerChange() {
|
|
17763
17801
|
const ranges = this.env.model.getters.getSelectionInputValue(this.id);
|
|
17764
17802
|
this.props.onSelectionChanged?.(ranges);
|
|
17765
|
-
this.previousRanges = ranges;
|
|
17766
17803
|
}
|
|
17767
17804
|
onKeydown(ev) {
|
|
17768
17805
|
if (ev.key === "F2") {
|
|
@@ -17812,10 +17849,37 @@ class SelectionInput extends Component {
|
|
|
17812
17849
|
});
|
|
17813
17850
|
this.triggerChange();
|
|
17814
17851
|
}
|
|
17852
|
+
reset() {
|
|
17853
|
+
const existingSelectionRanges = this.env.model.getters.getSelectionInput(this.id);
|
|
17854
|
+
for (const range of existingSelectionRanges) {
|
|
17855
|
+
this.env.model.dispatch("REMOVE_RANGE", {
|
|
17856
|
+
id: this.id,
|
|
17857
|
+
rangeId: range.id,
|
|
17858
|
+
});
|
|
17859
|
+
}
|
|
17860
|
+
for (const range of this.previousRanges) {
|
|
17861
|
+
this.env.model.dispatch("ADD_RANGE", { id: this.id, value: range });
|
|
17862
|
+
}
|
|
17863
|
+
this.confirm();
|
|
17864
|
+
}
|
|
17815
17865
|
confirm() {
|
|
17816
|
-
|
|
17817
|
-
const
|
|
17818
|
-
|
|
17866
|
+
let anyValidInput = false;
|
|
17867
|
+
const existingSelectionRanges = this.env.model.getters.getSelectionInput(this.id);
|
|
17868
|
+
const existingSelectionXcs = [];
|
|
17869
|
+
for (const range of existingSelectionRanges) {
|
|
17870
|
+
if (range.xc === "") {
|
|
17871
|
+
this.env.model.dispatch("REMOVE_RANGE", {
|
|
17872
|
+
id: this.id,
|
|
17873
|
+
rangeId: range.id,
|
|
17874
|
+
});
|
|
17875
|
+
continue;
|
|
17876
|
+
}
|
|
17877
|
+
existingSelectionXcs.push(range.xc);
|
|
17878
|
+
if (this.env.model.getters.isRangeValid(range.xc)) {
|
|
17879
|
+
anyValidInput = true;
|
|
17880
|
+
}
|
|
17881
|
+
}
|
|
17882
|
+
if (this.props.required && !anyValidInput) {
|
|
17819
17883
|
this.state.isMissing = true;
|
|
17820
17884
|
}
|
|
17821
17885
|
const activeSheetId = this.env.model.getters.getActiveSheetId();
|
|
@@ -17825,11 +17889,17 @@ class SelectionInput extends Component {
|
|
|
17825
17889
|
sheetIdTo: this.originSheet,
|
|
17826
17890
|
});
|
|
17827
17891
|
}
|
|
17892
|
+
this.props.onSelectionChanged?.(existingSelectionXcs);
|
|
17828
17893
|
this.props.onSelectionConfirmed?.();
|
|
17894
|
+
this.previousRanges = this.props.ranges();
|
|
17895
|
+
if (existingSelectionXcs.join() !== this.previousRanges.join()) {
|
|
17896
|
+
this.enableNewSelectionInput();
|
|
17897
|
+
}
|
|
17898
|
+
this.env.model.dispatch("UNFOCUS_SELECTION_INPUT");
|
|
17829
17899
|
}
|
|
17830
17900
|
}
|
|
17831
17901
|
SelectionInput.props = {
|
|
17832
|
-
ranges:
|
|
17902
|
+
ranges: Function,
|
|
17833
17903
|
hasSingleRange: { type: Boolean, optional: true },
|
|
17834
17904
|
required: { type: Boolean, optional: true },
|
|
17835
17905
|
isInvalid: { type: Boolean, optional: true },
|
|
@@ -17865,7 +17935,7 @@ class LineBarPieConfigPanel extends Component {
|
|
|
17865
17935
|
return !!this.state.labelsDispatchResult?.isCancelledBecause(33 /* CommandResult.InvalidLabelRange */);
|
|
17866
17936
|
}
|
|
17867
17937
|
onUpdateDataSetsHaveTitle(ev) {
|
|
17868
|
-
this.props.updateChart({
|
|
17938
|
+
this.props.updateChart(this.props.figureId, {
|
|
17869
17939
|
dataSetsHaveTitle: ev.target.checked,
|
|
17870
17940
|
});
|
|
17871
17941
|
}
|
|
@@ -17877,10 +17947,14 @@ class LineBarPieConfigPanel extends Component {
|
|
|
17877
17947
|
this.dataSeriesRanges = ranges;
|
|
17878
17948
|
}
|
|
17879
17949
|
onDataSeriesConfirmed() {
|
|
17880
|
-
this.
|
|
17950
|
+
this.dataSeriesRanges = spreadRange(this.dataSeriesRanges);
|
|
17951
|
+
this.state.datasetDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
17881
17952
|
dataSets: this.dataSeriesRanges,
|
|
17882
17953
|
});
|
|
17883
17954
|
}
|
|
17955
|
+
getDataSeriesRanges() {
|
|
17956
|
+
return this.dataSeriesRanges;
|
|
17957
|
+
}
|
|
17884
17958
|
/**
|
|
17885
17959
|
* Change the local labelRange. The model should be updated when the
|
|
17886
17960
|
* button "confirm" is clicked
|
|
@@ -17889,12 +17963,15 @@ class LineBarPieConfigPanel extends Component {
|
|
|
17889
17963
|
this.labelRange = ranges[0];
|
|
17890
17964
|
}
|
|
17891
17965
|
onLabelRangeConfirmed() {
|
|
17892
|
-
this.state.labelsDispatchResult = this.props.updateChart({
|
|
17966
|
+
this.state.labelsDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
17893
17967
|
labelRange: this.labelRange,
|
|
17894
17968
|
});
|
|
17895
17969
|
}
|
|
17970
|
+
getLabelRange() {
|
|
17971
|
+
return this.labelRange || "";
|
|
17972
|
+
}
|
|
17896
17973
|
onUpdateAggregated(ev) {
|
|
17897
|
-
this.props.updateChart({
|
|
17974
|
+
this.props.updateChart(this.props.figureId, {
|
|
17898
17975
|
aggregated: ev.target.checked,
|
|
17899
17976
|
});
|
|
17900
17977
|
}
|
|
@@ -17924,12 +18001,12 @@ LineBarPieConfigPanel.props = {
|
|
|
17924
18001
|
class BarConfigPanel extends LineBarPieConfigPanel {
|
|
17925
18002
|
static template = "o-spreadsheet-BarConfigPanel";
|
|
17926
18003
|
onUpdateStacked(ev) {
|
|
17927
|
-
this.props.updateChart({
|
|
18004
|
+
this.props.updateChart(this.props.figureId, {
|
|
17928
18005
|
stacked: ev.target.checked,
|
|
17929
18006
|
});
|
|
17930
18007
|
}
|
|
17931
18008
|
onUpdateAggregated(ev) {
|
|
17932
|
-
this.props.updateChart({
|
|
18009
|
+
this.props.updateChart(this.props.figureId, {
|
|
17933
18010
|
aggregated: ev.target.checked,
|
|
17934
18011
|
});
|
|
17935
18012
|
}
|
|
@@ -18266,17 +18343,17 @@ class LineBarPieDesignPanel extends Component {
|
|
|
18266
18343
|
this.state.fillColorTool = !this.state.fillColorTool;
|
|
18267
18344
|
}
|
|
18268
18345
|
updateBackgroundColor(color) {
|
|
18269
|
-
this.props.updateChart({
|
|
18346
|
+
this.props.updateChart(this.props.figureId, {
|
|
18270
18347
|
background: color,
|
|
18271
18348
|
});
|
|
18272
18349
|
}
|
|
18273
18350
|
updateTitle(ev) {
|
|
18274
|
-
this.props.updateChart({
|
|
18351
|
+
this.props.updateChart(this.props.figureId, {
|
|
18275
18352
|
title: ev.target.value,
|
|
18276
18353
|
});
|
|
18277
18354
|
}
|
|
18278
18355
|
updateSelect(attr, ev) {
|
|
18279
|
-
this.props.updateChart({
|
|
18356
|
+
this.props.updateChart(this.props.figureId, {
|
|
18280
18357
|
[attr]: ev.target.value,
|
|
18281
18358
|
});
|
|
18282
18359
|
}
|
|
@@ -18309,10 +18386,13 @@ class GaugeChartConfigPanel extends Component {
|
|
|
18309
18386
|
this.dataRange = ranges[0];
|
|
18310
18387
|
}
|
|
18311
18388
|
updateDataRange() {
|
|
18312
|
-
this.state.dataRangeDispatchResult = this.props.updateChart({
|
|
18389
|
+
this.state.dataRangeDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
18313
18390
|
dataRange: this.dataRange,
|
|
18314
18391
|
});
|
|
18315
18392
|
}
|
|
18393
|
+
getDataRange() {
|
|
18394
|
+
return this.dataRange || "";
|
|
18395
|
+
}
|
|
18316
18396
|
}
|
|
18317
18397
|
GaugeChartConfigPanel.props = {
|
|
18318
18398
|
figureId: String,
|
|
@@ -18367,12 +18447,12 @@ class GaugeChartDesignPanel extends Component {
|
|
|
18367
18447
|
}
|
|
18368
18448
|
updateBackgroundColor(color) {
|
|
18369
18449
|
this.state.openedMenu = undefined;
|
|
18370
|
-
this.props.updateChart({
|
|
18450
|
+
this.props.updateChart(this.props.figureId, {
|
|
18371
18451
|
background: color,
|
|
18372
18452
|
});
|
|
18373
18453
|
}
|
|
18374
18454
|
updateTitle(ev) {
|
|
18375
|
-
this.props.updateChart({
|
|
18455
|
+
this.props.updateChart(this.props.figureId, {
|
|
18376
18456
|
title: ev.target.value,
|
|
18377
18457
|
});
|
|
18378
18458
|
}
|
|
@@ -18437,7 +18517,7 @@ class GaugeChartDesignPanel extends Component {
|
|
|
18437
18517
|
}
|
|
18438
18518
|
}
|
|
18439
18519
|
updateSectionRule(sectionRule) {
|
|
18440
|
-
this.state.sectionRuleDispatchResult = this.props.updateChart({
|
|
18520
|
+
this.state.sectionRuleDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
18441
18521
|
sectionRule,
|
|
18442
18522
|
});
|
|
18443
18523
|
}
|
|
@@ -18461,17 +18541,17 @@ class LineConfigPanel extends LineBarPieConfigPanel {
|
|
|
18461
18541
|
return false;
|
|
18462
18542
|
}
|
|
18463
18543
|
onUpdateLabelsAsText(ev) {
|
|
18464
|
-
this.props.updateChart({
|
|
18544
|
+
this.props.updateChart(this.props.figureId, {
|
|
18465
18545
|
labelsAsText: ev.target.checked,
|
|
18466
18546
|
});
|
|
18467
18547
|
}
|
|
18468
18548
|
onUpdateStacked(ev) {
|
|
18469
|
-
this.props.updateChart({
|
|
18549
|
+
this.props.updateChart(this.props.figureId, {
|
|
18470
18550
|
stacked: ev.target.checked,
|
|
18471
18551
|
});
|
|
18472
18552
|
}
|
|
18473
18553
|
onUpdateAggregated(ev) {
|
|
18474
|
-
this.props.updateChart({
|
|
18554
|
+
this.props.updateChart(this.props.figureId, {
|
|
18475
18555
|
aggregated: ev.target.checked,
|
|
18476
18556
|
});
|
|
18477
18557
|
}
|
|
@@ -18507,20 +18587,26 @@ class ScorecardChartConfigPanel extends Component {
|
|
|
18507
18587
|
this.keyValue = ranges[0];
|
|
18508
18588
|
}
|
|
18509
18589
|
updateKeyValueRange() {
|
|
18510
|
-
this.state.keyValueDispatchResult = this.props.updateChart({
|
|
18590
|
+
this.state.keyValueDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
18511
18591
|
keyValue: this.keyValue,
|
|
18512
18592
|
});
|
|
18513
18593
|
}
|
|
18594
|
+
getKeyValueRange() {
|
|
18595
|
+
return this.keyValue || "";
|
|
18596
|
+
}
|
|
18514
18597
|
onBaselineRangeChanged(ranges) {
|
|
18515
18598
|
this.baseline = ranges[0];
|
|
18516
18599
|
}
|
|
18517
18600
|
updateBaselineRange() {
|
|
18518
|
-
this.state.baselineDispatchResult = this.props.updateChart({
|
|
18601
|
+
this.state.baselineDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
18519
18602
|
baseline: this.baseline,
|
|
18520
18603
|
});
|
|
18521
18604
|
}
|
|
18605
|
+
getBaselineRange() {
|
|
18606
|
+
return this.baseline || "";
|
|
18607
|
+
}
|
|
18522
18608
|
updateBaselineMode(ev) {
|
|
18523
|
-
this.props.updateChart({ baselineMode: ev.target.value });
|
|
18609
|
+
this.props.updateChart(this.props.figureId, { baselineMode: ev.target.value });
|
|
18524
18610
|
}
|
|
18525
18611
|
}
|
|
18526
18612
|
ScorecardChartConfigPanel.props = {
|
|
@@ -18539,12 +18625,12 @@ class ScorecardChartDesignPanel extends Component {
|
|
|
18539
18625
|
useExternalListener(window, "click", this.closeMenus);
|
|
18540
18626
|
}
|
|
18541
18627
|
updateTitle(ev) {
|
|
18542
|
-
this.props.updateChart({
|
|
18628
|
+
this.props.updateChart(this.props.figureId, {
|
|
18543
18629
|
title: ev.target.value,
|
|
18544
18630
|
});
|
|
18545
18631
|
}
|
|
18546
18632
|
updateBaselineDescr(ev) {
|
|
18547
|
-
this.props.updateChart({ baselineDescr: ev.target.value });
|
|
18633
|
+
this.props.updateChart(this.props.figureId, { baselineDescr: ev.target.value });
|
|
18548
18634
|
}
|
|
18549
18635
|
toggleColorPicker(colorPickerId) {
|
|
18550
18636
|
if (this.state.openedColorPicker === colorPickerId) {
|
|
@@ -18557,13 +18643,13 @@ class ScorecardChartDesignPanel extends Component {
|
|
|
18557
18643
|
setColor(color, colorPickerId) {
|
|
18558
18644
|
switch (colorPickerId) {
|
|
18559
18645
|
case "backgroundColor":
|
|
18560
|
-
this.props.updateChart({ background: color });
|
|
18646
|
+
this.props.updateChart(this.props.figureId, { background: color });
|
|
18561
18647
|
break;
|
|
18562
18648
|
case "baselineColorDown":
|
|
18563
|
-
this.props.updateChart({ baselineColorDown: color });
|
|
18649
|
+
this.props.updateChart(this.props.figureId, { baselineColorDown: color });
|
|
18564
18650
|
break;
|
|
18565
18651
|
case "baselineColorUp":
|
|
18566
|
-
this.props.updateChart({ baselineColorUp: color });
|
|
18652
|
+
this.props.updateChart(this.props.figureId, { baselineColorUp: color });
|
|
18567
18653
|
break;
|
|
18568
18654
|
}
|
|
18569
18655
|
this.closeMenus();
|
|
@@ -18628,13 +18714,9 @@ css /* scss */ `
|
|
|
18628
18714
|
class ChartPanel extends Component {
|
|
18629
18715
|
static template = "o-spreadsheet-ChartPanel";
|
|
18630
18716
|
state;
|
|
18631
|
-
shouldUpdateChart = true;
|
|
18632
18717
|
get figureId() {
|
|
18633
18718
|
return this.state.figureId;
|
|
18634
18719
|
}
|
|
18635
|
-
get sheetId() {
|
|
18636
|
-
return this.state.sheetId;
|
|
18637
|
-
}
|
|
18638
18720
|
setup() {
|
|
18639
18721
|
const selectedFigureId = this.env.model.getters.getSelectedFigureId();
|
|
18640
18722
|
if (!selectedFigureId) {
|
|
@@ -18644,17 +18726,11 @@ class ChartPanel extends Component {
|
|
|
18644
18726
|
this.state = useState({
|
|
18645
18727
|
panel: "configuration",
|
|
18646
18728
|
figureId: selectedFigureId,
|
|
18647
|
-
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
18648
18729
|
});
|
|
18649
18730
|
onWillUpdateProps(() => {
|
|
18650
18731
|
const selectedFigureId = this.env.model.getters.getSelectedFigureId();
|
|
18651
18732
|
if (selectedFigureId && selectedFigureId !== this.state.figureId) {
|
|
18652
18733
|
this.state.figureId = selectedFigureId;
|
|
18653
|
-
this.state.sheetId = this.env.model.getters.getActiveSheetId();
|
|
18654
|
-
this.shouldUpdateChart = false;
|
|
18655
|
-
}
|
|
18656
|
-
else {
|
|
18657
|
-
this.shouldUpdateChart = true;
|
|
18658
18734
|
}
|
|
18659
18735
|
if (!this.env.model.getters.isChartDefined(this.figureId)) {
|
|
18660
18736
|
this.props.onCloseSidePanel();
|
|
@@ -18662,8 +18738,8 @@ class ChartPanel extends Component {
|
|
|
18662
18738
|
}
|
|
18663
18739
|
});
|
|
18664
18740
|
}
|
|
18665
|
-
updateChart(updateDefinition) {
|
|
18666
|
-
if (
|
|
18741
|
+
updateChart(figureId, updateDefinition) {
|
|
18742
|
+
if (figureId !== this.figureId) {
|
|
18667
18743
|
return;
|
|
18668
18744
|
}
|
|
18669
18745
|
const definition = {
|
|
@@ -18672,8 +18748,8 @@ class ChartPanel extends Component {
|
|
|
18672
18748
|
};
|
|
18673
18749
|
return this.env.model.dispatch("UPDATE_CHART", {
|
|
18674
18750
|
definition,
|
|
18675
|
-
id:
|
|
18676
|
-
sheetId: this.
|
|
18751
|
+
id: figureId,
|
|
18752
|
+
sheetId: this.env.model.getters.getFigureSheetId(figureId),
|
|
18677
18753
|
});
|
|
18678
18754
|
}
|
|
18679
18755
|
onTypeChange(type) {
|
|
@@ -18685,7 +18761,7 @@ class ChartPanel extends Component {
|
|
|
18685
18761
|
this.env.model.dispatch("UPDATE_CHART", {
|
|
18686
18762
|
definition,
|
|
18687
18763
|
id: this.figureId,
|
|
18688
|
-
sheetId: this.
|
|
18764
|
+
sheetId: this.env.model.getters.getFigureSheetId(this.figureId),
|
|
18689
18765
|
});
|
|
18690
18766
|
}
|
|
18691
18767
|
get chartPanel() {
|
|
@@ -20481,12 +20557,23 @@ class ContentEditableHelper {
|
|
|
20481
20557
|
*/
|
|
20482
20558
|
selectRange(start, end) {
|
|
20483
20559
|
let selection = window.getSelection();
|
|
20484
|
-
this.
|
|
20485
|
-
|
|
20560
|
+
const { start: currentStart, end: currentEnd } = this.getCurrentSelection();
|
|
20561
|
+
if (currentStart === start && currentEnd === end) {
|
|
20562
|
+
return;
|
|
20563
|
+
}
|
|
20564
|
+
const currentRange = selection.getRangeAt(0);
|
|
20565
|
+
let range;
|
|
20566
|
+
if (this.el.contains(currentRange.startContainer)) {
|
|
20567
|
+
range = currentRange;
|
|
20568
|
+
}
|
|
20569
|
+
else {
|
|
20570
|
+
range = document.createRange();
|
|
20571
|
+
selection.removeAllRanges();
|
|
20572
|
+
selection.addRange(range);
|
|
20573
|
+
}
|
|
20486
20574
|
if (start == end && start === 0) {
|
|
20487
20575
|
range.setStart(this.el, 0);
|
|
20488
20576
|
range.setEnd(this.el, 0);
|
|
20489
|
-
selection.addRange(range);
|
|
20490
20577
|
}
|
|
20491
20578
|
else {
|
|
20492
20579
|
const textLength = this.getText().length;
|
|
@@ -20502,7 +20589,6 @@ class ContentEditableHelper {
|
|
|
20502
20589
|
let startNode = this.findChildAtCharacterIndex(start);
|
|
20503
20590
|
let endNode = this.findChildAtCharacterIndex(end);
|
|
20504
20591
|
range.setStart(startNode.node, startNode.offset);
|
|
20505
|
-
selection.addRange(range);
|
|
20506
20592
|
selection.extend(endNode.node, endNode.offset);
|
|
20507
20593
|
}
|
|
20508
20594
|
}
|
|
@@ -20542,26 +20628,54 @@ class ContentEditableHelper {
|
|
|
20542
20628
|
return { node: previous, offset: usedCharacters };
|
|
20543
20629
|
}
|
|
20544
20630
|
/**
|
|
20545
|
-
* Sets (or Replaces all) the text inside the root element in the form of distinctive
|
|
20631
|
+
* Sets (or Replaces all) the text inside the root element in the form of distinctive paragraphs and
|
|
20546
20632
|
* span for each element provided in `contents`.
|
|
20547
20633
|
*
|
|
20634
|
+
* The function will apply the diff between the current content and the new content to avoid the systematic
|
|
20635
|
+
* destruction of DOM elements which interferes with IME[1]
|
|
20636
|
+
*
|
|
20637
|
+
* Each line of text will be encapsulated in a paragraph element.
|
|
20548
20638
|
* Each span will have its own fontcolor and specific class if provided in the HtmlContent object.
|
|
20639
|
+
*
|
|
20640
|
+
* [1] https://developer.mozilla.org/en-US/docs/Glossary/Input_method_editor
|
|
20549
20641
|
*/
|
|
20550
20642
|
setText(contents) {
|
|
20551
|
-
this.el.innerHTML = "";
|
|
20552
20643
|
if (contents.length === 0) {
|
|
20644
|
+
this.removeAll();
|
|
20553
20645
|
return;
|
|
20554
20646
|
}
|
|
20555
|
-
|
|
20556
|
-
|
|
20557
|
-
|
|
20558
|
-
|
|
20559
|
-
|
|
20560
|
-
|
|
20561
|
-
|
|
20647
|
+
const childElements = Array.from(this.el.childNodes);
|
|
20648
|
+
const contentLength = contents.length;
|
|
20649
|
+
for (let i = 0; i < contentLength; i++) {
|
|
20650
|
+
const line = contents[i];
|
|
20651
|
+
const childElement = childElements[i];
|
|
20652
|
+
let newChild = false;
|
|
20653
|
+
let p;
|
|
20654
|
+
if (childElement && childElement.nodeName === "P") {
|
|
20655
|
+
p = childElement;
|
|
20562
20656
|
}
|
|
20563
|
-
|
|
20657
|
+
else {
|
|
20658
|
+
newChild = true;
|
|
20659
|
+
p = document.createElement("p");
|
|
20660
|
+
}
|
|
20661
|
+
const lineLength = line.length;
|
|
20662
|
+
const existingChildren = Array.from(p.childNodes);
|
|
20663
|
+
for (let j = 0; j < lineLength; j++) {
|
|
20664
|
+
const content = line[j];
|
|
20665
|
+
const child = existingChildren[j];
|
|
20666
|
+
// child nodes can be multiple types of nodes: Span, Text, Div, etc...
|
|
20667
|
+
// We can only modify a node in place if it has the same type as the content
|
|
20668
|
+
// that we would insert, which are spans.
|
|
20669
|
+
// Otherwise, it means that the node has been input by the user, through the keyboard or a copy/paste
|
|
20670
|
+
// @ts-ignore (somehow required because jest does not like child.tagName despite the prior check)
|
|
20671
|
+
const childIsSpan = child && "tagName" in child && child.tagName === "SPAN";
|
|
20672
|
+
if (childIsSpan && compareContentToSpanElement(content, child)) {
|
|
20673
|
+
continue;
|
|
20674
|
+
}
|
|
20675
|
+
// this is an empty line in the content
|
|
20564
20676
|
if (!content.value && !content.class) {
|
|
20677
|
+
if (child)
|
|
20678
|
+
p.removeChild(child);
|
|
20565
20679
|
continue;
|
|
20566
20680
|
}
|
|
20567
20681
|
const span = document.createElement("span");
|
|
@@ -20570,9 +20684,38 @@ class ContentEditableHelper {
|
|
|
20570
20684
|
if (content.class) {
|
|
20571
20685
|
span.classList.add(content.class);
|
|
20572
20686
|
}
|
|
20687
|
+
if (child) {
|
|
20688
|
+
p.replaceChild(span, child);
|
|
20689
|
+
}
|
|
20690
|
+
else {
|
|
20691
|
+
p.appendChild(span);
|
|
20692
|
+
}
|
|
20693
|
+
}
|
|
20694
|
+
if (existingChildren.length > lineLength) {
|
|
20695
|
+
for (let i = lineLength; i < existingChildren.length; i++) {
|
|
20696
|
+
p.removeChild(existingChildren[i]);
|
|
20697
|
+
}
|
|
20698
|
+
}
|
|
20699
|
+
// Empty line
|
|
20700
|
+
if (!p.hasChildNodes()) {
|
|
20701
|
+
const span = document.createElement("span");
|
|
20702
|
+
span.appendChild(document.createElement("br"));
|
|
20573
20703
|
p.appendChild(span);
|
|
20574
20704
|
}
|
|
20575
|
-
|
|
20705
|
+
// replace p if necessary
|
|
20706
|
+
if (newChild) {
|
|
20707
|
+
if (childElement) {
|
|
20708
|
+
this.el.replaceChild(p, childElement);
|
|
20709
|
+
}
|
|
20710
|
+
else {
|
|
20711
|
+
this.el.appendChild(p);
|
|
20712
|
+
}
|
|
20713
|
+
}
|
|
20714
|
+
}
|
|
20715
|
+
if (childElements.length > contentLength) {
|
|
20716
|
+
for (let i = contentLength; i < childElements.length; i++) {
|
|
20717
|
+
this.el.removeChild(childElements[i]);
|
|
20718
|
+
}
|
|
20576
20719
|
}
|
|
20577
20720
|
}
|
|
20578
20721
|
scrollSelectionIntoView() {
|
|
@@ -20582,13 +20725,6 @@ class ContentEditableHelper {
|
|
|
20582
20725
|
const element = focusedNode instanceof HTMLElement ? focusedNode : focusedNode.parentElement;
|
|
20583
20726
|
element?.scrollIntoView({ block: "nearest" });
|
|
20584
20727
|
}
|
|
20585
|
-
/**
|
|
20586
|
-
* remove the current selection of the user
|
|
20587
|
-
* */
|
|
20588
|
-
removeSelection() {
|
|
20589
|
-
let selection = window.getSelection();
|
|
20590
|
-
selection.removeAllRanges();
|
|
20591
|
-
}
|
|
20592
20728
|
removeAll() {
|
|
20593
20729
|
if (this.el) {
|
|
20594
20730
|
while (this.el.firstChild) {
|
|
@@ -20718,6 +20854,14 @@ class ContentEditableHelper {
|
|
|
20718
20854
|
}
|
|
20719
20855
|
return text;
|
|
20720
20856
|
}
|
|
20857
|
+
}
|
|
20858
|
+
function compareContentToSpanElement(content, node) {
|
|
20859
|
+
const contentColor = content.color ? toHex(content.color) : "";
|
|
20860
|
+
const nodeColor = node.style?.color ? toHex(node.style.color) : "";
|
|
20861
|
+
const sameColor = contentColor === nodeColor;
|
|
20862
|
+
const sameClass = deepEquals([content.class], [...node.classList]);
|
|
20863
|
+
const sameContent = node.innerText === content.value;
|
|
20864
|
+
return sameColor && sameClass && sameContent;
|
|
20721
20865
|
}
|
|
20722
20866
|
|
|
20723
20867
|
// -----------------------------------------------------------------------------
|
|
@@ -20863,7 +21007,6 @@ class Composer extends Component {
|
|
|
20863
21007
|
functionDescription: {},
|
|
20864
21008
|
argToFocus: 0,
|
|
20865
21009
|
});
|
|
20866
|
-
isKeyStillDown = false;
|
|
20867
21010
|
compositionActive = false;
|
|
20868
21011
|
get assistantStyle() {
|
|
20869
21012
|
if (this.props.delimitation && this.props.rect) {
|
|
@@ -20898,21 +21041,18 @@ class Composer extends Component {
|
|
|
20898
21041
|
F2: () => console.warn("Not implemented"),
|
|
20899
21042
|
F4: this.processF4Key,
|
|
20900
21043
|
Tab: (ev) => this.processTabKey(ev),
|
|
21044
|
+
" ": (ev) => this.processSpaceKey(ev),
|
|
20901
21045
|
};
|
|
20902
21046
|
setup() {
|
|
20903
21047
|
onMounted(() => {
|
|
20904
21048
|
const el = this.composerRef.el;
|
|
20905
21049
|
this.contentHelper.updateEl(el);
|
|
20906
|
-
this.processContent();
|
|
20907
|
-
this.contentHelper.scrollSelectionIntoView();
|
|
20908
21050
|
});
|
|
20909
21051
|
onWillUnmount(() => {
|
|
20910
21052
|
this.props.onComposerUnmounted?.();
|
|
20911
21053
|
});
|
|
20912
|
-
|
|
20913
|
-
|
|
20914
|
-
this.processContent();
|
|
20915
|
-
}
|
|
21054
|
+
useEffect(() => {
|
|
21055
|
+
this.processContent();
|
|
20916
21056
|
});
|
|
20917
21057
|
}
|
|
20918
21058
|
// ---------------------------------------------------------------------------
|
|
@@ -20965,32 +21105,25 @@ class Composer extends Component {
|
|
|
20965
21105
|
return;
|
|
20966
21106
|
}
|
|
20967
21107
|
}
|
|
20968
|
-
else {
|
|
20969
|
-
// when completing with tab, if there is no value to complete, the active cell will be moved to the right.
|
|
20970
|
-
// we can't let the model think that it is for a ref selection.
|
|
20971
|
-
// todo: check if this can be removed someday
|
|
20972
|
-
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
20973
|
-
}
|
|
20974
21108
|
const direction = ev.shiftKey ? "left" : "right";
|
|
20975
21109
|
this.env.model.dispatch("STOP_EDITION");
|
|
20976
21110
|
this.env.model.selection.moveAnchorCell(direction, 1);
|
|
20977
21111
|
}
|
|
21112
|
+
processSpaceKey(ev) {
|
|
21113
|
+
if (ev.ctrlKey) {
|
|
21114
|
+
ev.preventDefault();
|
|
21115
|
+
ev.stopPropagation();
|
|
21116
|
+
this.showAutocomplete("");
|
|
21117
|
+
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
21118
|
+
}
|
|
21119
|
+
}
|
|
20978
21120
|
processEnterKey(ev) {
|
|
20979
21121
|
ev.preventDefault();
|
|
20980
21122
|
ev.stopPropagation();
|
|
20981
21123
|
if (ev.altKey || ev.ctrlKey) {
|
|
20982
|
-
|
|
20983
|
-
const currentContent = this.env.model.getters.getCurrentContent();
|
|
20984
|
-
const content = currentContent.slice(0, selection.start) + NEWLINE + currentContent.slice(selection.end);
|
|
20985
|
-
this.env.model.dispatch("SET_CURRENT_CONTENT", {
|
|
20986
|
-
content,
|
|
20987
|
-
selection: { start: selection.start + 1, end: selection.start + 1 },
|
|
20988
|
-
});
|
|
20989
|
-
this.processContent();
|
|
20990
|
-
this.contentHelper.scrollSelectionIntoView();
|
|
21124
|
+
this.composerRef.el?.dispatchEvent(new InputEvent("input", { inputType: "insertParagraph", bubbles: true, isComposing: false }));
|
|
20991
21125
|
return;
|
|
20992
21126
|
}
|
|
20993
|
-
this.isKeyStillDown = false;
|
|
20994
21127
|
if (this.autoCompleteState.showProvider) {
|
|
20995
21128
|
const autoCompleteValue = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]?.text;
|
|
20996
21129
|
if (autoCompleteValue) {
|
|
@@ -21023,56 +21156,42 @@ class Composer extends Component {
|
|
|
21023
21156
|
else {
|
|
21024
21157
|
ev.stopPropagation();
|
|
21025
21158
|
}
|
|
21026
|
-
const { start, end } = this.contentHelper.getCurrentSelection();
|
|
21027
|
-
if (!this.env.model.getters.isSelectingForComposer() &&
|
|
21028
|
-
!(ev.key === "Enter" && (ev.altKey || ev.ctrlKey))) {
|
|
21029
|
-
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", { start, end });
|
|
21030
|
-
this.isKeyStillDown = true;
|
|
21031
|
-
}
|
|
21032
21159
|
}
|
|
21033
21160
|
/*
|
|
21034
21161
|
* Triggered automatically by the content-editable between the keydown and key up
|
|
21035
21162
|
* */
|
|
21036
|
-
onInput() {
|
|
21163
|
+
onInput(ev) {
|
|
21037
21164
|
if (this.props.focus === "inactive" || !this.shouldProcessInputEvents) {
|
|
21038
21165
|
return;
|
|
21039
21166
|
}
|
|
21167
|
+
let content = this.contentHelper.getText();
|
|
21168
|
+
let selection = this.contentHelper.getCurrentSelection();
|
|
21169
|
+
if (ev.inputType === "insertParagraph") {
|
|
21170
|
+
const start = Math.min(selection.start, selection.end);
|
|
21171
|
+
const end = Math.max(selection.start, selection.end);
|
|
21172
|
+
content = content.slice(0, start) + NEWLINE + content.slice(end);
|
|
21173
|
+
selection = { start: start + 1, end: start + 1 };
|
|
21174
|
+
}
|
|
21040
21175
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
21041
21176
|
this.env.model.dispatch("SET_CURRENT_CONTENT", {
|
|
21042
|
-
content
|
|
21043
|
-
selection
|
|
21177
|
+
content,
|
|
21178
|
+
selection,
|
|
21044
21179
|
});
|
|
21180
|
+
this.processTokenAtCursor();
|
|
21045
21181
|
}
|
|
21046
|
-
onKeyup(
|
|
21047
|
-
this.
|
|
21048
|
-
|
|
21049
|
-
|
|
21050
|
-
|
|
21051
|
-
|
|
21052
|
-
|
|
21053
|
-
return; // already processed in keydown
|
|
21054
|
-
}
|
|
21055
|
-
if (this.env.model.getters.isSelectingForComposer() &&
|
|
21056
|
-
["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(ev.key)) {
|
|
21057
|
-
return; // already processed in keydown
|
|
21058
|
-
}
|
|
21059
|
-
ev.preventDefault();
|
|
21060
|
-
ev.stopPropagation();
|
|
21061
|
-
this.autoCompleteState.showProvider = false;
|
|
21062
|
-
if (ev.ctrlKey && ev.key === " ") {
|
|
21063
|
-
this.showAutocomplete("");
|
|
21064
|
-
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
21065
|
-
return;
|
|
21066
|
-
}
|
|
21067
|
-
const { start: oldStart, end: oldEnd } = this.env.model.getters.getComposerSelection();
|
|
21068
|
-
const { start, end } = this.contentHelper.getCurrentSelection();
|
|
21069
|
-
if (start !== oldStart || end !== oldEnd) {
|
|
21070
|
-
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", this.contentHelper.getCurrentSelection());
|
|
21182
|
+
onKeyup() {
|
|
21183
|
+
if (this.contentHelper.el === document.activeElement) {
|
|
21184
|
+
const { start: oldStart, end: oldEnd } = this.env.model.getters.getComposerSelection();
|
|
21185
|
+
const { start, end } = this.contentHelper.getCurrentSelection();
|
|
21186
|
+
if (start !== oldStart || end !== oldEnd) {
|
|
21187
|
+
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", { start, end });
|
|
21188
|
+
}
|
|
21071
21189
|
}
|
|
21072
|
-
this.processTokenAtCursor();
|
|
21073
|
-
this.processContent();
|
|
21074
21190
|
}
|
|
21075
21191
|
showAutocomplete(searchTerm) {
|
|
21192
|
+
if (!this.env.model.getters.getCurrentContent().startsWith("=")) {
|
|
21193
|
+
return;
|
|
21194
|
+
}
|
|
21076
21195
|
this.autoCompleteState.showProvider = true;
|
|
21077
21196
|
let values = Object.entries(functionRegistry.content)
|
|
21078
21197
|
.filter(([_, { hidden }]) => !hidden)
|
|
@@ -21092,13 +21211,6 @@ class Composer extends Component {
|
|
|
21092
21211
|
this.autoCompleteState.values = values.slice(0, 10);
|
|
21093
21212
|
this.autoCompleteState.selectedIndex = 0;
|
|
21094
21213
|
}
|
|
21095
|
-
onMousedown(ev) {
|
|
21096
|
-
if (ev.button > 0) {
|
|
21097
|
-
// not main button, probably a context menu
|
|
21098
|
-
return;
|
|
21099
|
-
}
|
|
21100
|
-
this.contentHelper.removeSelection();
|
|
21101
|
-
}
|
|
21102
21214
|
onClick() {
|
|
21103
21215
|
if (this.env.model.getters.isReadonly()) {
|
|
21104
21216
|
return;
|
|
@@ -21111,9 +21223,6 @@ class Composer extends Component {
|
|
|
21111
21223
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
|
|
21112
21224
|
this.processTokenAtCursor();
|
|
21113
21225
|
}
|
|
21114
|
-
onBlur() {
|
|
21115
|
-
this.isKeyStillDown = false;
|
|
21116
|
-
}
|
|
21117
21226
|
// ---------------------------------------------------------------------------
|
|
21118
21227
|
// Private
|
|
21119
21228
|
// ---------------------------------------------------------------------------
|
|
@@ -21121,22 +21230,19 @@ class Composer extends Component {
|
|
|
21121
21230
|
if (this.compositionActive) {
|
|
21122
21231
|
return;
|
|
21123
21232
|
}
|
|
21124
|
-
const oldScroll = getElementScrollTop(this.composerRef.el);
|
|
21125
|
-
this.contentHelper.removeAll(); // removes the content of the composer, to be added just after
|
|
21126
21233
|
this.shouldProcessInputEvents = false;
|
|
21127
21234
|
if (this.props.focus !== "inactive") {
|
|
21128
21235
|
this.contentHelper.el.focus();
|
|
21129
|
-
this.contentHelper.selectRange(0, 0); // move the cursor inside the composer at 0 0.
|
|
21130
21236
|
}
|
|
21131
21237
|
const content = this.getContentLines();
|
|
21238
|
+
this.contentHelper.setText(content);
|
|
21132
21239
|
if (content.length !== 0 && content.length[0] !== 0) {
|
|
21133
|
-
this.contentHelper.setText(content);
|
|
21134
|
-
const { start, end } = this.env.model.getters.getComposerSelection();
|
|
21135
21240
|
if (this.props.focus !== "inactive") {
|
|
21136
21241
|
// Put the cursor back where it was before the rendering
|
|
21242
|
+
const { start, end } = this.env.model.getters.getComposerSelection();
|
|
21137
21243
|
this.contentHelper.selectRange(start, end);
|
|
21138
21244
|
}
|
|
21139
|
-
|
|
21245
|
+
this.contentHelper.scrollSelectionIntoView();
|
|
21140
21246
|
}
|
|
21141
21247
|
this.shouldProcessInputEvents = true;
|
|
21142
21248
|
}
|
|
@@ -21391,8 +21497,8 @@ class GridComposer extends Component {
|
|
|
21391
21497
|
height: el.clientHeight,
|
|
21392
21498
|
};
|
|
21393
21499
|
this.composerState.delimitation = {
|
|
21394
|
-
width:
|
|
21395
|
-
height:
|
|
21500
|
+
width: this.props.gridDims.width,
|
|
21501
|
+
height: this.props.gridDims.height,
|
|
21396
21502
|
};
|
|
21397
21503
|
});
|
|
21398
21504
|
onWillUpdateProps(() => {
|
|
@@ -23110,7 +23216,7 @@ class Highlight extends Component {
|
|
|
23110
23216
|
shiftingMode: "none",
|
|
23111
23217
|
});
|
|
23112
23218
|
onResizeHighlight(isLeft, isTop) {
|
|
23113
|
-
const
|
|
23219
|
+
const activeSheetId = this.env.model.getters.getActiveSheetId();
|
|
23114
23220
|
this.highlightState.shiftingMode = "isResizing";
|
|
23115
23221
|
const z = this.props.zone;
|
|
23116
23222
|
const pivotCol = isLeft ? z.right : z.left;
|
|
@@ -23119,11 +23225,10 @@ class Highlight extends Component {
|
|
|
23119
23225
|
let lastRow = isTop ? z.top : z.bottom;
|
|
23120
23226
|
let currentZone = z;
|
|
23121
23227
|
this.env.model.dispatch("START_CHANGE_HIGHLIGHT", {
|
|
23122
|
-
range: this.env.model.getters.getRangeDataFromZone(
|
|
23228
|
+
range: this.env.model.getters.getRangeDataFromZone(activeSheetId, currentZone),
|
|
23123
23229
|
});
|
|
23124
23230
|
const mouseMove = (col, row) => {
|
|
23125
23231
|
if (lastCol !== col || lastRow !== row) {
|
|
23126
|
-
const activeSheetId = this.env.model.getters.getActiveSheetId();
|
|
23127
23232
|
lastCol = clip(col === -1 ? lastCol : col, 0, this.env.model.getters.getNumberCols(activeSheetId) - 1);
|
|
23128
23233
|
lastRow = clip(row === -1 ? lastRow : row, 0, this.env.model.getters.getNumberRows(activeSheetId) - 1);
|
|
23129
23234
|
let newZone = {
|
|
@@ -23135,7 +23240,7 @@ class Highlight extends Component {
|
|
|
23135
23240
|
newZone = this.env.model.getters.expandZone(activeSheetId, newZone);
|
|
23136
23241
|
if (!isEqual(newZone, currentZone)) {
|
|
23137
23242
|
this.env.model.dispatch("CHANGE_HIGHLIGHT", {
|
|
23138
|
-
range: this.env.model.getters.
|
|
23243
|
+
range: this.env.model.getters.getRangeFromZone(activeSheetId, this.env.model.getters.getUnboundedZone(activeSheetId, newZone)).rangeData,
|
|
23139
23244
|
});
|
|
23140
23245
|
currentZone = newZone;
|
|
23141
23246
|
}
|
|
@@ -23182,7 +23287,7 @@ class Highlight extends Component {
|
|
|
23182
23287
|
newZone = this.env.model.getters.expandZone(activeSheetId, newZone);
|
|
23183
23288
|
if (!isEqual(newZone, currentZone)) {
|
|
23184
23289
|
this.env.model.dispatch("CHANGE_HIGHLIGHT", {
|
|
23185
|
-
range: this.env.model.getters.
|
|
23290
|
+
range: this.env.model.getters.getRangeFromZone(activeSheetId, this.env.model.getters.getUnboundedZone(activeSheetId, newZone)).rangeData,
|
|
23186
23291
|
});
|
|
23187
23292
|
currentZone = newZone;
|
|
23188
23293
|
}
|
|
@@ -24504,6 +24609,16 @@ const XLSX_INDEXED_COLORS = {
|
|
|
24504
24609
|
63: "333333",
|
|
24505
24610
|
64: "000000",
|
|
24506
24611
|
65: "FFFFFF", // system background
|
|
24612
|
+
};
|
|
24613
|
+
const IMAGE_MIMETYPE_EXTENSION_MAPPING = {
|
|
24614
|
+
"image/avif": "avif",
|
|
24615
|
+
"image/bmp": "bmp",
|
|
24616
|
+
"image/gif": "gif",
|
|
24617
|
+
"image/vnd.microsoft.icon": "ico",
|
|
24618
|
+
"image/jpeg": "jpeg",
|
|
24619
|
+
"image/png": "png",
|
|
24620
|
+
"image/tiff": "tiff",
|
|
24621
|
+
"image/webp": "webp",
|
|
24507
24622
|
};
|
|
24508
24623
|
|
|
24509
24624
|
/**
|
|
@@ -26986,6 +27101,11 @@ function createOverride(partName, contentType) {
|
|
|
26986
27101
|
<Override ContentType="${contentType}" PartName="${partName}" />
|
|
26987
27102
|
`;
|
|
26988
27103
|
}
|
|
27104
|
+
function createDefaultXMLElement(extension, contentType) {
|
|
27105
|
+
return escapeXml /*xml*/ `
|
|
27106
|
+
<Default Extension="${extension}" ContentType="${contentType}" />
|
|
27107
|
+
`;
|
|
27108
|
+
}
|
|
26989
27109
|
function joinXmlNodes(xmlNodes) {
|
|
26990
27110
|
return new XMLString(xmlNodes.join("\n"));
|
|
26991
27111
|
}
|
|
@@ -28851,11 +28971,9 @@ class BasePlugin {
|
|
|
28851
28971
|
*/
|
|
28852
28972
|
class CorePlugin extends BasePlugin {
|
|
28853
28973
|
getters;
|
|
28854
|
-
range;
|
|
28855
28974
|
uuidGenerator;
|
|
28856
28975
|
constructor({ getters, stateObserver, range, dispatch, uuidGenerator }) {
|
|
28857
28976
|
super(stateObserver, dispatch);
|
|
28858
|
-
this.range = range;
|
|
28859
28977
|
range.addRangeProvider(this.adaptRanges.bind(this));
|
|
28860
28978
|
this.getters = getters;
|
|
28861
28979
|
this.uuidGenerator = uuidGenerator;
|
|
@@ -31429,6 +31547,7 @@ class MergePlugin extends CorePlugin {
|
|
|
31429
31547
|
"getMerge",
|
|
31430
31548
|
"getMergesInZone",
|
|
31431
31549
|
"isSingleCellOrMerge",
|
|
31550
|
+
"getSelectionRangeString",
|
|
31432
31551
|
];
|
|
31433
31552
|
nextId = 1;
|
|
31434
31553
|
merges = {};
|
|
@@ -31516,6 +31635,26 @@ class MergePlugin extends CorePlugin {
|
|
|
31516
31635
|
.map((mergeId) => this.getMergeById(sheetId, mergeId))
|
|
31517
31636
|
.filter(isDefined$1);
|
|
31518
31637
|
}
|
|
31638
|
+
/**
|
|
31639
|
+
* Same as `getRangeString` but add all necessary merge to the range to make it a valid selection
|
|
31640
|
+
*/
|
|
31641
|
+
getSelectionRangeString(range, forSheetId) {
|
|
31642
|
+
const rangeImpl = RangeImpl.fromRange(range, this.getters);
|
|
31643
|
+
const expandedZone = this.getters.expandZone(rangeImpl.sheetId, rangeImpl.zone);
|
|
31644
|
+
const expandedRange = rangeImpl.clone({
|
|
31645
|
+
zone: {
|
|
31646
|
+
...expandedZone,
|
|
31647
|
+
bottom: rangeImpl.isFullCol ? undefined : expandedZone.bottom,
|
|
31648
|
+
right: rangeImpl.isFullRow ? undefined : expandedZone.right,
|
|
31649
|
+
},
|
|
31650
|
+
});
|
|
31651
|
+
const rangeString = this.getters.getRangeString(expandedRange, forSheetId);
|
|
31652
|
+
if (this.isSingleCellOrMerge(rangeImpl.sheetId, rangeImpl.zone)) {
|
|
31653
|
+
const { sheetName, xc } = splitReference(rangeString);
|
|
31654
|
+
return `${sheetName !== undefined ? getCanonicalSheetName(sheetName) + "!" : ""}${xc.split(":")[0]}`;
|
|
31655
|
+
}
|
|
31656
|
+
return rangeString;
|
|
31657
|
+
}
|
|
31519
31658
|
/**
|
|
31520
31659
|
* Return true if the zone intersects an existing merge:
|
|
31521
31660
|
* if they have at least a common cell
|
|
@@ -31848,12 +31987,12 @@ class RangeAdapter {
|
|
|
31848
31987
|
}
|
|
31849
31988
|
static getters = [
|
|
31850
31989
|
"getRangeString",
|
|
31851
|
-
"getSelectionRangeString",
|
|
31852
31990
|
"getRangeFromSheetXC",
|
|
31853
31991
|
"createAdaptedRanges",
|
|
31854
31992
|
"getRangeDataFromXc",
|
|
31855
31993
|
"getRangeDataFromZone",
|
|
31856
31994
|
"getRangeFromRangeData",
|
|
31995
|
+
"getRangeFromZone",
|
|
31857
31996
|
];
|
|
31858
31997
|
// ---------------------------------------------------------------------------
|
|
31859
31998
|
// Command Handling
|
|
@@ -32102,21 +32241,6 @@ class RangeAdapter {
|
|
|
32102
32241
|
const rangeInterface = { prefixSheet, zone, sheetId, invalidSheetName, parts };
|
|
32103
32242
|
return new RangeImpl(rangeInterface, this.getters.getSheetSize).orderZone();
|
|
32104
32243
|
}
|
|
32105
|
-
/**
|
|
32106
|
-
* Same as `getRangeString` but add all necessary merge to the range to make it a valid selection
|
|
32107
|
-
*/
|
|
32108
|
-
getSelectionRangeString(range, forSheetId) {
|
|
32109
|
-
const rangeImpl = RangeImpl.fromRange(range, this.getters);
|
|
32110
|
-
const expandedZone = this.getters.expandZone(rangeImpl.sheetId, rangeImpl.zone);
|
|
32111
|
-
const expandedRange = rangeImpl.clone({
|
|
32112
|
-
zone: {
|
|
32113
|
-
...expandedZone,
|
|
32114
|
-
bottom: rangeImpl.isFullCol ? undefined : expandedZone.bottom,
|
|
32115
|
-
right: rangeImpl.isFullRow ? undefined : expandedZone.right,
|
|
32116
|
-
},
|
|
32117
|
-
});
|
|
32118
|
-
return this.getRangeString(expandedRange, forSheetId);
|
|
32119
|
-
}
|
|
32120
32244
|
/**
|
|
32121
32245
|
* Gets the string that represents the range as it is at the moment of the call.
|
|
32122
32246
|
* The string will be prefixed with the sheet name if the call specified a sheet id in `forSheetId`
|
|
@@ -32173,6 +32297,17 @@ class RangeAdapter {
|
|
|
32173
32297
|
getRangeDataFromZone(sheetId, zone) {
|
|
32174
32298
|
return { _sheetId: sheetId, _zone: zone };
|
|
32175
32299
|
}
|
|
32300
|
+
getRangeFromZone(sheetId, zone) {
|
|
32301
|
+
return new RangeImpl({
|
|
32302
|
+
sheetId,
|
|
32303
|
+
zone,
|
|
32304
|
+
parts: [
|
|
32305
|
+
{ colFixed: false, rowFixed: false },
|
|
32306
|
+
{ colFixed: false, rowFixed: false },
|
|
32307
|
+
],
|
|
32308
|
+
prefixSheet: false,
|
|
32309
|
+
}, this.getters.getSheetSize);
|
|
32310
|
+
}
|
|
32176
32311
|
getRangeFromRangeData(data) {
|
|
32177
32312
|
const rangeInterface = {
|
|
32178
32313
|
prefixSheet: false,
|
|
@@ -32258,6 +32393,7 @@ class SheetPlugin extends CorePlugin {
|
|
|
32258
32393
|
"getPaneDivisions",
|
|
32259
32394
|
"checkZonesExistInSheet",
|
|
32260
32395
|
"getCommandZones",
|
|
32396
|
+
"getUnboundedZone",
|
|
32261
32397
|
];
|
|
32262
32398
|
sheetIdsMapName = {};
|
|
32263
32399
|
orderedSheetIds = [];
|
|
@@ -32583,6 +32719,16 @@ class SheetPlugin extends CorePlugin {
|
|
|
32583
32719
|
right: this.getNumberCols(sheetId) - 1,
|
|
32584
32720
|
};
|
|
32585
32721
|
}
|
|
32722
|
+
getUnboundedZone(sheetId, zone) {
|
|
32723
|
+
const isFullRow = zone.left === 0 && zone.right === this.getNumberCols(sheetId) - 1;
|
|
32724
|
+
const isFullCol = zone.top === 0 && zone.bottom === this.getNumberRows(sheetId) - 1;
|
|
32725
|
+
return {
|
|
32726
|
+
...zone,
|
|
32727
|
+
bottom: isFullCol ? undefined : zone.bottom,
|
|
32728
|
+
// cannot be unbounded in the 2 dimensions at once
|
|
32729
|
+
right: isFullRow && !isFullCol ? undefined : zone.right,
|
|
32730
|
+
};
|
|
32731
|
+
}
|
|
32586
32732
|
getPaneDivisions(sheetId) {
|
|
32587
32733
|
return this.getSheet(sheetId).panes;
|
|
32588
32734
|
}
|
|
@@ -38618,6 +38764,7 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
38618
38764
|
// ---------------------------------------------------------------------------
|
|
38619
38765
|
allowDispatch(cmd) {
|
|
38620
38766
|
switch (cmd.type) {
|
|
38767
|
+
case "ADD_RANGE":
|
|
38621
38768
|
case "ADD_EMPTY_RANGE":
|
|
38622
38769
|
if (this.inputHasSingleRange && this.ranges.length === 1) {
|
|
38623
38770
|
return 30 /* CommandResult.MaximumRangesReached */;
|
|
@@ -38632,11 +38779,11 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
38632
38779
|
return 0 /* CommandResult.Success */;
|
|
38633
38780
|
}
|
|
38634
38781
|
handleEvent(event) {
|
|
38635
|
-
const xc = zoneToXc(event.anchor.zone);
|
|
38636
38782
|
const inputSheetId = this.activeSheet;
|
|
38637
38783
|
const sheetId = this.getters.getActiveSheetId();
|
|
38638
|
-
const
|
|
38639
|
-
this.
|
|
38784
|
+
const zone = event.anchor.zone;
|
|
38785
|
+
const range = this.getters.getRangeFromZone(sheetId, event.type === "HeadersSelected" ? this.getters.getUnboundedZone(sheetId, zone) : zone);
|
|
38786
|
+
this.add([this.getters.getSelectionRangeString(range, inputSheetId)]);
|
|
38640
38787
|
}
|
|
38641
38788
|
handle(cmd) {
|
|
38642
38789
|
switch (cmd.type) {
|
|
@@ -38662,6 +38809,10 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
38662
38809
|
this.insertNewRange(this.ranges.length, [""]);
|
|
38663
38810
|
this.focusLast();
|
|
38664
38811
|
break;
|
|
38812
|
+
case "ADD_RANGE":
|
|
38813
|
+
this.insertNewRange(this.ranges.length, [cmd.value]);
|
|
38814
|
+
this.focusLast();
|
|
38815
|
+
break;
|
|
38665
38816
|
case "REMOVE_RANGE":
|
|
38666
38817
|
const index = this.getIndex(cmd.rangeId);
|
|
38667
38818
|
if (index !== null) {
|
|
@@ -38873,6 +39024,7 @@ class SelectionInputsManagerPlugin extends UIPlugin {
|
|
|
38873
39024
|
case "UNFOCUS_SELECTION_INPUT":
|
|
38874
39025
|
this.unfocus();
|
|
38875
39026
|
break;
|
|
39027
|
+
case "ADD_RANGE":
|
|
38876
39028
|
case "ADD_EMPTY_RANGE":
|
|
38877
39029
|
case "REMOVE_RANGE":
|
|
38878
39030
|
if (cmd.id !== this.focusedInputId) {
|
|
@@ -38886,9 +39038,11 @@ class SelectionInputsManagerPlugin extends UIPlugin {
|
|
|
38886
39038
|
if (cmd.id !== this.focusedInputId) {
|
|
38887
39039
|
const input = this.inputs[cmd.id];
|
|
38888
39040
|
const range = input.ranges.find((range) => range.id === cmd.rangeId);
|
|
38889
|
-
|
|
38890
|
-
|
|
38891
|
-
|
|
39041
|
+
if (this.isRangeValid(range?.xc || "A1")) {
|
|
39042
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
39043
|
+
const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
|
|
39044
|
+
this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, { handleEvent: input.handleEvent.bind(input) });
|
|
39045
|
+
}
|
|
38892
39046
|
this.focusedInputId = cmd.id;
|
|
38893
39047
|
}
|
|
38894
39048
|
break;
|
|
@@ -41087,12 +41241,20 @@ class EditionPlugin extends UIPlugin {
|
|
|
41087
41241
|
if (this.mode !== "selecting") {
|
|
41088
41242
|
return;
|
|
41089
41243
|
}
|
|
41244
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
41245
|
+
let unboundedZone;
|
|
41246
|
+
if (event.type === "HeadersSelected") {
|
|
41247
|
+
unboundedZone = this.getters.getUnboundedZone(sheetId, event.anchor.zone);
|
|
41248
|
+
}
|
|
41249
|
+
else {
|
|
41250
|
+
unboundedZone = event.anchor.zone;
|
|
41251
|
+
}
|
|
41090
41252
|
switch (event.mode) {
|
|
41091
41253
|
case "newAnchor":
|
|
41092
|
-
this.insertSelectedRange(
|
|
41254
|
+
this.insertSelectedRange(unboundedZone);
|
|
41093
41255
|
break;
|
|
41094
41256
|
default:
|
|
41095
|
-
this.replaceSelectedRanges(
|
|
41257
|
+
this.replaceSelectedRanges(unboundedZone);
|
|
41096
41258
|
break;
|
|
41097
41259
|
}
|
|
41098
41260
|
}
|
|
@@ -41149,7 +41311,9 @@ class EditionPlugin extends UIPlugin {
|
|
|
41149
41311
|
}
|
|
41150
41312
|
break;
|
|
41151
41313
|
case "START_CHANGE_HIGHLIGHT":
|
|
41314
|
+
// FIXME: thiws whole ordeal could be handled with the Selection Processor which would extend the feature to selection inputs
|
|
41152
41315
|
this.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
41316
|
+
// FIXME: we should check range SheetId compared to this.activeSheetId r maybe not have a sheetId in the payload ??
|
|
41153
41317
|
const range = this.getters.getRangeFromRangeData(cmd.range);
|
|
41154
41318
|
const previousRefToken = this.currentTokens
|
|
41155
41319
|
.filter((token) => token.type === "REFERENCE")
|
|
@@ -41503,14 +41667,11 @@ class EditionPlugin extends UIPlugin {
|
|
|
41503
41667
|
const ref = this.getZoneReference(zone);
|
|
41504
41668
|
this.replaceText(ref, this.selectionInitialStart, this.selectionEnd);
|
|
41505
41669
|
}
|
|
41506
|
-
getZoneReference(zone
|
|
41670
|
+
getZoneReference(zone) {
|
|
41671
|
+
const inputSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
41507
41672
|
const sheetId = this.getters.getActiveSheetId();
|
|
41508
|
-
|
|
41509
|
-
|
|
41510
|
-
const sheetName = getCanonicalSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
|
|
41511
|
-
selectedXc = `${sheetName}!${selectedXc}`;
|
|
41512
|
-
}
|
|
41513
|
-
return selectedXc;
|
|
41673
|
+
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
41674
|
+
return this.getters.getSelectionRangeString(range, inputSheetId);
|
|
41514
41675
|
}
|
|
41515
41676
|
getRangeReference(range, fixedParts = [{ colFixed: false, rowFixed: false }]) {
|
|
41516
41677
|
let _fixedParts = [...fixedParts];
|
|
@@ -42364,7 +42525,7 @@ class ImageProvider {
|
|
|
42364
42525
|
const file = await this.getImageFromUser();
|
|
42365
42526
|
const path = await this.fileStore.upload(file);
|
|
42366
42527
|
const size = await this.getImageSize(path);
|
|
42367
|
-
return { path, size };
|
|
42528
|
+
return { path, size, mimetype: file.type };
|
|
42368
42529
|
}
|
|
42369
42530
|
getImageFromUser() {
|
|
42370
42531
|
return new Promise((resolve, reject) => {
|
|
@@ -47431,8 +47592,7 @@ function createWorksheets(data, construct) {
|
|
|
47431
47592
|
// Figures and Charts
|
|
47432
47593
|
let drawingNode = escapeXml ``;
|
|
47433
47594
|
const drawingRelIds = [];
|
|
47434
|
-
const
|
|
47435
|
-
for (const chart of charts) {
|
|
47595
|
+
for (const chart of sheet.charts) {
|
|
47436
47596
|
const xlsxChartId = convertChartId(chart.id);
|
|
47437
47597
|
const chartRelId = addRelsToFile(construct.relsFiles, `xl/drawings/_rels/drawing${sheetIndex}.xml.rels`, {
|
|
47438
47598
|
target: `../charts/chart${xlsxChartId}.xml`,
|
|
@@ -47441,20 +47601,27 @@ function createWorksheets(data, construct) {
|
|
|
47441
47601
|
drawingRelIds.push(chartRelId);
|
|
47442
47602
|
files.push(createXMLFile(createChart(chart, sheetIndex, data), `xl/charts/chart${xlsxChartId}.xml`, "chart"));
|
|
47443
47603
|
}
|
|
47444
|
-
const
|
|
47445
|
-
|
|
47604
|
+
for (const image of sheet.images) {
|
|
47605
|
+
const mimeType = image.data.mimetype;
|
|
47606
|
+
if (mimeType === undefined)
|
|
47607
|
+
continue;
|
|
47608
|
+
const extension = IMAGE_MIMETYPE_EXTENSION_MAPPING[mimeType];
|
|
47609
|
+
// only support exporting images with mimetypes specified in the mapping
|
|
47610
|
+
if (extension === undefined)
|
|
47611
|
+
continue;
|
|
47446
47612
|
const xlsxImageId = convertImageId(image.id);
|
|
47613
|
+
let imageFileName = `image${xlsxImageId}.${extension}`;
|
|
47447
47614
|
const imageRelId = addRelsToFile(construct.relsFiles, `xl/drawings/_rels/drawing${sheetIndex}.xml.rels`, {
|
|
47448
|
-
target: `../media
|
|
47615
|
+
target: `../media/${imageFileName}`,
|
|
47449
47616
|
type: XLSX_RELATION_TYPE.image,
|
|
47450
47617
|
});
|
|
47451
47618
|
drawingRelIds.push(imageRelId);
|
|
47452
47619
|
files.push({
|
|
47453
|
-
path: `xl/media
|
|
47454
|
-
|
|
47620
|
+
path: `xl/media/${imageFileName}`,
|
|
47621
|
+
imageSrc: image.data.path,
|
|
47455
47622
|
});
|
|
47456
47623
|
}
|
|
47457
|
-
const drawings = [...charts, ...images];
|
|
47624
|
+
const drawings = [...sheet.charts, ...sheet.images];
|
|
47458
47625
|
if (drawings.length) {
|
|
47459
47626
|
const drawingRelId = addRelsToFile(construct.relsFiles, `xl/worksheets/_rels/sheet${sheetIndex}.xml.rels`, {
|
|
47460
47627
|
target: `../drawings/drawing${sheetIndex}.xml`,
|
|
@@ -47573,6 +47740,8 @@ function createRelsFiles(relsFiles) {
|
|
|
47573
47740
|
}
|
|
47574
47741
|
function createContentTypes(files) {
|
|
47575
47742
|
const overrideNodes = [];
|
|
47743
|
+
// hard-code supported image mimetypes
|
|
47744
|
+
const imageDefaultNodes = Object.entries(IMAGE_MIMETYPE_EXTENSION_MAPPING).map(([mimetype, extension]) => createDefaultXMLElement(extension, mimetype));
|
|
47576
47745
|
for (const file of files) {
|
|
47577
47746
|
if ("contentType" in file && file.contentType) {
|
|
47578
47747
|
overrideNodes.push(createOverride("/" + file.path, CONTENT_TYPES[file.contentType]));
|
|
@@ -47588,6 +47757,7 @@ function createContentTypes(files) {
|
|
|
47588
47757
|
];
|
|
47589
47758
|
const xml = escapeXml /*xml*/ `
|
|
47590
47759
|
<Types xmlns="${NAMESPACE["Types"]}">
|
|
47760
|
+
${joinXmlNodes(Object.values(imageDefaultNodes))}
|
|
47591
47761
|
<Default ${formatAttributes(relsAttributes)} />
|
|
47592
47762
|
<Default ${formatAttributes(xmlAttributes)} />
|
|
47593
47763
|
${joinXmlNodes(overrideNodes)}
|
|
@@ -47679,7 +47849,7 @@ class Model extends EventBus {
|
|
|
47679
47849
|
this.coreGetters.getRangeDataFromXc = this.range.getRangeDataFromXc.bind(this.range);
|
|
47680
47850
|
this.coreGetters.getRangeDataFromZone = this.range.getRangeDataFromZone.bind(this.range);
|
|
47681
47851
|
this.coreGetters.getRangeFromRangeData = this.range.getRangeFromRangeData.bind(this.range);
|
|
47682
|
-
this.coreGetters.
|
|
47852
|
+
this.coreGetters.getRangeFromZone = this.range.getRangeFromZone.bind(this.range);
|
|
47683
47853
|
this.getters = {
|
|
47684
47854
|
isReadonly: () => this.config.mode === "readonly" || this.config.mode === "dashboard",
|
|
47685
47855
|
isDashboard: () => this.config.mode === "dashboard",
|
|
@@ -48167,9 +48337,9 @@ function addFunction(functionName, functionDescription) {
|
|
|
48167
48337
|
functionRegistry.add(functionName, functionDescription);
|
|
48168
48338
|
}
|
|
48169
48339
|
|
|
48170
|
-
export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateEvaluationCommands, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
|
|
48340
|
+
export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
|
|
48171
48341
|
|
|
48172
48342
|
|
|
48173
|
-
__info__.version = '16.4.0-alpha.
|
|
48174
|
-
__info__.date = '2023-
|
|
48175
|
-
__info__.hash = '
|
|
48343
|
+
__info__.version = '16.4.0-alpha.3';
|
|
48344
|
+
__info__.date = '2023-06-02T10:13:30.127Z';
|
|
48345
|
+
__info__.hash = '059d66a';
|