@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
|
@@ -2218,249 +2218,6 @@ function splitReference(ref) {
|
|
|
2218
2218
|
return { sheetName, xc };
|
|
2219
2219
|
}
|
|
2220
2220
|
|
|
2221
|
-
class RangeImpl {
|
|
2222
|
-
getSheetSize;
|
|
2223
|
-
_zone;
|
|
2224
|
-
parts;
|
|
2225
|
-
invalidXc;
|
|
2226
|
-
prefixSheet = false;
|
|
2227
|
-
sheetId; // the sheet on which the range is defined
|
|
2228
|
-
invalidSheetName; // the name of any sheet that is invalid
|
|
2229
|
-
constructor(args, getSheetSize) {
|
|
2230
|
-
this.getSheetSize = getSheetSize;
|
|
2231
|
-
this._zone = args.zone;
|
|
2232
|
-
this.parts = args.parts;
|
|
2233
|
-
this.prefixSheet = args.prefixSheet;
|
|
2234
|
-
this.invalidXc = args.invalidXc;
|
|
2235
|
-
this.sheetId = args.sheetId;
|
|
2236
|
-
this.invalidSheetName = args.invalidSheetName;
|
|
2237
|
-
}
|
|
2238
|
-
static fromRange(range, getters) {
|
|
2239
|
-
if (range instanceof RangeImpl) {
|
|
2240
|
-
return range;
|
|
2241
|
-
}
|
|
2242
|
-
return new RangeImpl(range, getters.getSheetSize);
|
|
2243
|
-
}
|
|
2244
|
-
get unboundedZone() {
|
|
2245
|
-
return this._zone;
|
|
2246
|
-
}
|
|
2247
|
-
get zone() {
|
|
2248
|
-
const { left, top, bottom, right } = this._zone;
|
|
2249
|
-
if (right !== undefined && bottom !== undefined)
|
|
2250
|
-
return { left, top, right, bottom };
|
|
2251
|
-
else if (bottom === undefined && right !== undefined) {
|
|
2252
|
-
return { right, top, left, bottom: this.getSheetSize(this.sheetId).numberOfRows - 1 };
|
|
2253
|
-
}
|
|
2254
|
-
else if (right === undefined && bottom !== undefined) {
|
|
2255
|
-
return { bottom, left, top, right: this.getSheetSize(this.sheetId).numberOfCols - 1 };
|
|
2256
|
-
}
|
|
2257
|
-
throw new Error(_lt("Bad zone format"));
|
|
2258
|
-
}
|
|
2259
|
-
static getRangeParts(xc, zone) {
|
|
2260
|
-
const parts = xc.split(":").map((p) => {
|
|
2261
|
-
const isFullRow = isRowReference(p);
|
|
2262
|
-
return {
|
|
2263
|
-
colFixed: isFullRow ? false : p.startsWith("$"),
|
|
2264
|
-
rowFixed: isFullRow ? p.startsWith("$") : p.includes("$", 1),
|
|
2265
|
-
};
|
|
2266
|
-
});
|
|
2267
|
-
const isFullCol = zone.bottom === undefined;
|
|
2268
|
-
const isFullRow = zone.right === undefined;
|
|
2269
|
-
if (isFullCol) {
|
|
2270
|
-
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2271
|
-
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2272
|
-
if (zone.left === zone.right) {
|
|
2273
|
-
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2274
|
-
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2275
|
-
}
|
|
2276
|
-
}
|
|
2277
|
-
if (isFullRow) {
|
|
2278
|
-
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2279
|
-
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2280
|
-
if (zone.top === zone.bottom) {
|
|
2281
|
-
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2282
|
-
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2283
|
-
}
|
|
2284
|
-
}
|
|
2285
|
-
return parts;
|
|
2286
|
-
}
|
|
2287
|
-
get isFullCol() {
|
|
2288
|
-
return this._zone.bottom === undefined;
|
|
2289
|
-
}
|
|
2290
|
-
get isFullRow() {
|
|
2291
|
-
return this._zone.right === undefined;
|
|
2292
|
-
}
|
|
2293
|
-
get rangeData() {
|
|
2294
|
-
return {
|
|
2295
|
-
_zone: this._zone,
|
|
2296
|
-
_sheetId: this.sheetId,
|
|
2297
|
-
};
|
|
2298
|
-
}
|
|
2299
|
-
/**
|
|
2300
|
-
* Check that a zone is valid regarding the order of top-bottom and left-right.
|
|
2301
|
-
* Left should be smaller than right, top should be smaller than bottom.
|
|
2302
|
-
* If it's not the case, simply invert them, and invert the linked parts
|
|
2303
|
-
*/
|
|
2304
|
-
orderZone() {
|
|
2305
|
-
const zone = { ...this._zone };
|
|
2306
|
-
let parts = this.parts;
|
|
2307
|
-
if (zone.right !== undefined && zone.right < zone.left) {
|
|
2308
|
-
let right = zone.right;
|
|
2309
|
-
zone.right = zone.left;
|
|
2310
|
-
zone.left = right;
|
|
2311
|
-
parts = [
|
|
2312
|
-
{
|
|
2313
|
-
colFixed: parts[1]?.colFixed || false,
|
|
2314
|
-
rowFixed: parts[0]?.rowFixed || false,
|
|
2315
|
-
},
|
|
2316
|
-
{
|
|
2317
|
-
colFixed: parts[0]?.colFixed || false,
|
|
2318
|
-
rowFixed: parts[1]?.rowFixed || false,
|
|
2319
|
-
},
|
|
2320
|
-
];
|
|
2321
|
-
}
|
|
2322
|
-
if (zone.bottom !== undefined && zone.bottom < zone.top) {
|
|
2323
|
-
let bottom = zone.bottom;
|
|
2324
|
-
zone.bottom = zone.top;
|
|
2325
|
-
zone.top = bottom;
|
|
2326
|
-
parts = [
|
|
2327
|
-
{
|
|
2328
|
-
colFixed: parts[0]?.colFixed || false,
|
|
2329
|
-
rowFixed: parts[1]?.rowFixed || false,
|
|
2330
|
-
},
|
|
2331
|
-
{
|
|
2332
|
-
colFixed: parts[1]?.colFixed || false,
|
|
2333
|
-
rowFixed: parts[0]?.rowFixed || false,
|
|
2334
|
-
},
|
|
2335
|
-
];
|
|
2336
|
-
}
|
|
2337
|
-
return this.clone({ zone, parts });
|
|
2338
|
-
}
|
|
2339
|
-
/**
|
|
2340
|
-
*
|
|
2341
|
-
* @param rangeParams optional, values to put in the cloned range instead of the current values of the range
|
|
2342
|
-
*/
|
|
2343
|
-
clone(rangeParams) {
|
|
2344
|
-
return new RangeImpl({
|
|
2345
|
-
zone: rangeParams?.zone ? rangeParams.zone : { ...this._zone },
|
|
2346
|
-
sheetId: rangeParams?.sheetId ? rangeParams.sheetId : this.sheetId,
|
|
2347
|
-
invalidSheetName: rangeParams && "invalidSheetName" in rangeParams // 'attr in obj' instead of just 'obj.attr' because we accept undefined values
|
|
2348
|
-
? rangeParams.invalidSheetName
|
|
2349
|
-
: this.invalidSheetName,
|
|
2350
|
-
invalidXc: rangeParams && "invalidXc" in rangeParams ? rangeParams.invalidXc : this.invalidXc,
|
|
2351
|
-
parts: rangeParams?.parts
|
|
2352
|
-
? rangeParams.parts
|
|
2353
|
-
: this.parts.map((part) => {
|
|
2354
|
-
return { rowFixed: part.rowFixed, colFixed: part.colFixed };
|
|
2355
|
-
}),
|
|
2356
|
-
prefixSheet: rangeParams?.prefixSheet ? rangeParams.prefixSheet : this.prefixSheet,
|
|
2357
|
-
}, this.getSheetSize);
|
|
2358
|
-
}
|
|
2359
|
-
}
|
|
2360
|
-
/**
|
|
2361
|
-
* Copy a range. If the range is on the sheetIdFrom, the range will target
|
|
2362
|
-
* sheetIdTo.
|
|
2363
|
-
*/
|
|
2364
|
-
function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
|
|
2365
|
-
const sheetId = range.sheetId === sheetIdFrom ? sheetIdTo : range.sheetId;
|
|
2366
|
-
return range.clone({ sheetId });
|
|
2367
|
-
}
|
|
2368
|
-
/**
|
|
2369
|
-
* Create a range from a xc. If the xc is empty, this function returns undefined.
|
|
2370
|
-
*/
|
|
2371
|
-
function createRange(getters, sheetId, range) {
|
|
2372
|
-
return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
|
|
2373
|
-
}
|
|
2374
|
-
|
|
2375
|
-
/** Methods from Odoo Web Utils */
|
|
2376
|
-
/**
|
|
2377
|
-
* This function computes a score that represent the fact that the
|
|
2378
|
-
* string contains the pattern, or not
|
|
2379
|
-
*
|
|
2380
|
-
* - If the score is 0, the string does not contain the letters of the pattern in
|
|
2381
|
-
* the correct order.
|
|
2382
|
-
* - if the score is > 0, it actually contains the letters.
|
|
2383
|
-
*
|
|
2384
|
-
* Better matches will get a higher score: consecutive letters are better,
|
|
2385
|
-
* and a match closer to the beginning of the string is also scored higher.
|
|
2386
|
-
*/
|
|
2387
|
-
function fuzzyMatch(pattern, str) {
|
|
2388
|
-
pattern = pattern.toLocaleLowerCase();
|
|
2389
|
-
str = str.toLocaleLowerCase();
|
|
2390
|
-
let totalScore = 0;
|
|
2391
|
-
let currentScore = 0;
|
|
2392
|
-
let len = str.length;
|
|
2393
|
-
let patternIndex = 0;
|
|
2394
|
-
for (let i = 0; i < len; i++) {
|
|
2395
|
-
if (str[i] === pattern[patternIndex]) {
|
|
2396
|
-
patternIndex++;
|
|
2397
|
-
currentScore += 100 + currentScore - i / 200;
|
|
2398
|
-
}
|
|
2399
|
-
else {
|
|
2400
|
-
currentScore = 0;
|
|
2401
|
-
}
|
|
2402
|
-
totalScore = totalScore + currentScore;
|
|
2403
|
-
}
|
|
2404
|
-
return patternIndex === pattern.length ? totalScore : 0;
|
|
2405
|
-
}
|
|
2406
|
-
/**
|
|
2407
|
-
* Return a list of things that matches a pattern, ordered by their 'score' (
|
|
2408
|
-
* higher score first). An higher score means that the match is better. For
|
|
2409
|
-
* example, consecutive letters are considered a better match.
|
|
2410
|
-
*/
|
|
2411
|
-
function fuzzyLookup(pattern, list, fn) {
|
|
2412
|
-
const results = [];
|
|
2413
|
-
list.forEach((data) => {
|
|
2414
|
-
const score = fuzzyMatch(pattern, fn(data));
|
|
2415
|
-
if (score > 0) {
|
|
2416
|
-
results.push({ score, elem: data });
|
|
2417
|
-
}
|
|
2418
|
-
});
|
|
2419
|
-
// we want better matches first
|
|
2420
|
-
results.sort((a, b) => b.score - a.score);
|
|
2421
|
-
return results.map((r) => r.elem);
|
|
2422
|
-
}
|
|
2423
|
-
|
|
2424
|
-
function createDefaultRows(rowNumber) {
|
|
2425
|
-
const rows = [];
|
|
2426
|
-
for (let i = 0; i < rowNumber; i++) {
|
|
2427
|
-
const row = {
|
|
2428
|
-
cells: {},
|
|
2429
|
-
};
|
|
2430
|
-
rows.push(row);
|
|
2431
|
-
}
|
|
2432
|
-
return rows;
|
|
2433
|
-
}
|
|
2434
|
-
|
|
2435
|
-
/*
|
|
2436
|
-
* https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
|
|
2437
|
-
* */
|
|
2438
|
-
class UuidGenerator {
|
|
2439
|
-
isFastIdStrategy = false;
|
|
2440
|
-
fastIdStart = 0;
|
|
2441
|
-
setIsFastStrategy(isFast) {
|
|
2442
|
-
this.isFastIdStrategy = isFast;
|
|
2443
|
-
}
|
|
2444
|
-
uuidv4() {
|
|
2445
|
-
if (this.isFastIdStrategy) {
|
|
2446
|
-
this.fastIdStart++;
|
|
2447
|
-
return String(this.fastIdStart);
|
|
2448
|
-
//@ts-ignore
|
|
2449
|
-
}
|
|
2450
|
-
else if (window.crypto && window.crypto.getRandomValues) {
|
|
2451
|
-
//@ts-ignore
|
|
2452
|
-
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16));
|
|
2453
|
-
}
|
|
2454
|
-
else {
|
|
2455
|
-
// mainly for jest and other browsers that do not have the crypto functionality
|
|
2456
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
2457
|
-
var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
|
|
2458
|
-
return v.toString(16);
|
|
2459
|
-
});
|
|
2460
|
-
}
|
|
2461
|
-
}
|
|
2462
|
-
}
|
|
2463
|
-
|
|
2464
2221
|
/**
|
|
2465
2222
|
* Convert from a cartesian reference to a Zone
|
|
2466
2223
|
* The range boundaries will be kept in the same order as the
|
|
@@ -3067,6 +2824,287 @@ function getZonesRows(zones) {
|
|
|
3067
2824
|
return set;
|
|
3068
2825
|
}
|
|
3069
2826
|
|
|
2827
|
+
class RangeImpl {
|
|
2828
|
+
getSheetSize;
|
|
2829
|
+
_zone;
|
|
2830
|
+
parts;
|
|
2831
|
+
invalidXc;
|
|
2832
|
+
prefixSheet = false;
|
|
2833
|
+
sheetId; // the sheet on which the range is defined
|
|
2834
|
+
invalidSheetName; // the name of any sheet that is invalid
|
|
2835
|
+
constructor(args, getSheetSize) {
|
|
2836
|
+
this.getSheetSize = getSheetSize;
|
|
2837
|
+
this._zone = args.zone;
|
|
2838
|
+
this.parts = args.parts;
|
|
2839
|
+
this.prefixSheet = args.prefixSheet;
|
|
2840
|
+
this.invalidXc = args.invalidXc;
|
|
2841
|
+
this.sheetId = args.sheetId;
|
|
2842
|
+
this.invalidSheetName = args.invalidSheetName;
|
|
2843
|
+
}
|
|
2844
|
+
static fromRange(range, getters) {
|
|
2845
|
+
if (range instanceof RangeImpl) {
|
|
2846
|
+
return range;
|
|
2847
|
+
}
|
|
2848
|
+
return new RangeImpl(range, getters.getSheetSize);
|
|
2849
|
+
}
|
|
2850
|
+
get unboundedZone() {
|
|
2851
|
+
return this._zone;
|
|
2852
|
+
}
|
|
2853
|
+
get zone() {
|
|
2854
|
+
const { left, top, bottom, right } = this._zone;
|
|
2855
|
+
if (right !== undefined && bottom !== undefined)
|
|
2856
|
+
return { left, top, right, bottom };
|
|
2857
|
+
else if (bottom === undefined && right !== undefined) {
|
|
2858
|
+
return { right, top, left, bottom: this.getSheetSize(this.sheetId).numberOfRows - 1 };
|
|
2859
|
+
}
|
|
2860
|
+
else if (right === undefined && bottom !== undefined) {
|
|
2861
|
+
return { bottom, left, top, right: this.getSheetSize(this.sheetId).numberOfCols - 1 };
|
|
2862
|
+
}
|
|
2863
|
+
throw new Error(_lt("Bad zone format"));
|
|
2864
|
+
}
|
|
2865
|
+
static getRangeParts(xc, zone) {
|
|
2866
|
+
const parts = xc.split(":").map((p) => {
|
|
2867
|
+
const isFullRow = isRowReference(p);
|
|
2868
|
+
return {
|
|
2869
|
+
colFixed: isFullRow ? false : p.startsWith("$"),
|
|
2870
|
+
rowFixed: isFullRow ? p.startsWith("$") : p.includes("$", 1),
|
|
2871
|
+
};
|
|
2872
|
+
});
|
|
2873
|
+
const isFullCol = zone.bottom === undefined;
|
|
2874
|
+
const isFullRow = zone.right === undefined;
|
|
2875
|
+
if (isFullCol) {
|
|
2876
|
+
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2877
|
+
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2878
|
+
if (zone.left === zone.right) {
|
|
2879
|
+
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2880
|
+
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
if (isFullRow) {
|
|
2884
|
+
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2885
|
+
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2886
|
+
if (zone.top === zone.bottom) {
|
|
2887
|
+
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2888
|
+
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
return parts;
|
|
2892
|
+
}
|
|
2893
|
+
get isFullCol() {
|
|
2894
|
+
return this._zone.bottom === undefined;
|
|
2895
|
+
}
|
|
2896
|
+
get isFullRow() {
|
|
2897
|
+
return this._zone.right === undefined;
|
|
2898
|
+
}
|
|
2899
|
+
get rangeData() {
|
|
2900
|
+
return {
|
|
2901
|
+
_zone: this._zone,
|
|
2902
|
+
_sheetId: this.sheetId,
|
|
2903
|
+
};
|
|
2904
|
+
}
|
|
2905
|
+
/**
|
|
2906
|
+
* Check that a zone is valid regarding the order of top-bottom and left-right.
|
|
2907
|
+
* Left should be smaller than right, top should be smaller than bottom.
|
|
2908
|
+
* If it's not the case, simply invert them, and invert the linked parts
|
|
2909
|
+
*/
|
|
2910
|
+
orderZone() {
|
|
2911
|
+
const zone = { ...this._zone };
|
|
2912
|
+
let parts = this.parts;
|
|
2913
|
+
if (zone.right !== undefined && zone.right < zone.left) {
|
|
2914
|
+
let right = zone.right;
|
|
2915
|
+
zone.right = zone.left;
|
|
2916
|
+
zone.left = right;
|
|
2917
|
+
parts = [
|
|
2918
|
+
{
|
|
2919
|
+
colFixed: parts[1]?.colFixed || false,
|
|
2920
|
+
rowFixed: parts[0]?.rowFixed || false,
|
|
2921
|
+
},
|
|
2922
|
+
{
|
|
2923
|
+
colFixed: parts[0]?.colFixed || false,
|
|
2924
|
+
rowFixed: parts[1]?.rowFixed || false,
|
|
2925
|
+
},
|
|
2926
|
+
];
|
|
2927
|
+
}
|
|
2928
|
+
if (zone.bottom !== undefined && zone.bottom < zone.top) {
|
|
2929
|
+
let bottom = zone.bottom;
|
|
2930
|
+
zone.bottom = zone.top;
|
|
2931
|
+
zone.top = bottom;
|
|
2932
|
+
parts = [
|
|
2933
|
+
{
|
|
2934
|
+
colFixed: parts[0]?.colFixed || false,
|
|
2935
|
+
rowFixed: parts[1]?.rowFixed || false,
|
|
2936
|
+
},
|
|
2937
|
+
{
|
|
2938
|
+
colFixed: parts[1]?.colFixed || false,
|
|
2939
|
+
rowFixed: parts[0]?.rowFixed || false,
|
|
2940
|
+
},
|
|
2941
|
+
];
|
|
2942
|
+
}
|
|
2943
|
+
return this.clone({ zone, parts });
|
|
2944
|
+
}
|
|
2945
|
+
/**
|
|
2946
|
+
*
|
|
2947
|
+
* @param rangeParams optional, values to put in the cloned range instead of the current values of the range
|
|
2948
|
+
*/
|
|
2949
|
+
clone(rangeParams) {
|
|
2950
|
+
return new RangeImpl({
|
|
2951
|
+
zone: rangeParams?.zone ? rangeParams.zone : { ...this._zone },
|
|
2952
|
+
sheetId: rangeParams?.sheetId ? rangeParams.sheetId : this.sheetId,
|
|
2953
|
+
invalidSheetName: rangeParams && "invalidSheetName" in rangeParams // 'attr in obj' instead of just 'obj.attr' because we accept undefined values
|
|
2954
|
+
? rangeParams.invalidSheetName
|
|
2955
|
+
: this.invalidSheetName,
|
|
2956
|
+
invalidXc: rangeParams && "invalidXc" in rangeParams ? rangeParams.invalidXc : this.invalidXc,
|
|
2957
|
+
parts: rangeParams?.parts
|
|
2958
|
+
? rangeParams.parts
|
|
2959
|
+
: this.parts.map((part) => {
|
|
2960
|
+
return { rowFixed: part.rowFixed, colFixed: part.colFixed };
|
|
2961
|
+
}),
|
|
2962
|
+
prefixSheet: rangeParams?.prefixSheet ? rangeParams.prefixSheet : this.prefixSheet,
|
|
2963
|
+
}, this.getSheetSize);
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
/**
|
|
2967
|
+
* Copy a range. If the range is on the sheetIdFrom, the range will target
|
|
2968
|
+
* sheetIdTo.
|
|
2969
|
+
*/
|
|
2970
|
+
function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
|
|
2971
|
+
const sheetId = range.sheetId === sheetIdFrom ? sheetIdTo : range.sheetId;
|
|
2972
|
+
return range.clone({ sheetId });
|
|
2973
|
+
}
|
|
2974
|
+
/**
|
|
2975
|
+
* Create a range from a xc. If the xc is empty, this function returns undefined.
|
|
2976
|
+
*/
|
|
2977
|
+
function createRange(getters, sheetId, range) {
|
|
2978
|
+
return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
|
|
2979
|
+
}
|
|
2980
|
+
/**
|
|
2981
|
+
* Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
|
|
2982
|
+
* For example, A1:B4 will become [A1:A4, B1:B4]
|
|
2983
|
+
*/
|
|
2984
|
+
function spreadRange(ranges) {
|
|
2985
|
+
const postProcessedRanges = [];
|
|
2986
|
+
for (const range of ranges) {
|
|
2987
|
+
const { sheetName } = splitReference(range);
|
|
2988
|
+
const sheetPrefix = sheetName ? `${sheetName}!` : "";
|
|
2989
|
+
const zone = toUnboundedZone(range);
|
|
2990
|
+
if (zone.bottom !== zone.top && zone.left != zone.right) {
|
|
2991
|
+
if (zone.right) {
|
|
2992
|
+
for (let j = zone.left; j <= zone.right; ++j) {
|
|
2993
|
+
postProcessedRanges.push(`${sheetPrefix}${zoneToXc({
|
|
2994
|
+
left: j,
|
|
2995
|
+
right: j,
|
|
2996
|
+
top: zone.top,
|
|
2997
|
+
bottom: zone.bottom,
|
|
2998
|
+
})}`);
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
else {
|
|
3002
|
+
for (let j = zone.top; j <= zone.bottom; ++j) {
|
|
3003
|
+
postProcessedRanges.push(`${sheetPrefix}${zoneToXc({
|
|
3004
|
+
left: zone.left,
|
|
3005
|
+
right: zone.right,
|
|
3006
|
+
top: j,
|
|
3007
|
+
bottom: j,
|
|
3008
|
+
})}`);
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
else {
|
|
3013
|
+
postProcessedRanges.push(range);
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
return postProcessedRanges;
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
/** Methods from Odoo Web Utils */
|
|
3020
|
+
/**
|
|
3021
|
+
* This function computes a score that represent the fact that the
|
|
3022
|
+
* string contains the pattern, or not
|
|
3023
|
+
*
|
|
3024
|
+
* - If the score is 0, the string does not contain the letters of the pattern in
|
|
3025
|
+
* the correct order.
|
|
3026
|
+
* - if the score is > 0, it actually contains the letters.
|
|
3027
|
+
*
|
|
3028
|
+
* Better matches will get a higher score: consecutive letters are better,
|
|
3029
|
+
* and a match closer to the beginning of the string is also scored higher.
|
|
3030
|
+
*/
|
|
3031
|
+
function fuzzyMatch(pattern, str) {
|
|
3032
|
+
pattern = pattern.toLocaleLowerCase();
|
|
3033
|
+
str = str.toLocaleLowerCase();
|
|
3034
|
+
let totalScore = 0;
|
|
3035
|
+
let currentScore = 0;
|
|
3036
|
+
let len = str.length;
|
|
3037
|
+
let patternIndex = 0;
|
|
3038
|
+
for (let i = 0; i < len; i++) {
|
|
3039
|
+
if (str[i] === pattern[patternIndex]) {
|
|
3040
|
+
patternIndex++;
|
|
3041
|
+
currentScore += 100 + currentScore - i / 200;
|
|
3042
|
+
}
|
|
3043
|
+
else {
|
|
3044
|
+
currentScore = 0;
|
|
3045
|
+
}
|
|
3046
|
+
totalScore = totalScore + currentScore;
|
|
3047
|
+
}
|
|
3048
|
+
return patternIndex === pattern.length ? totalScore : 0;
|
|
3049
|
+
}
|
|
3050
|
+
/**
|
|
3051
|
+
* Return a list of things that matches a pattern, ordered by their 'score' (
|
|
3052
|
+
* higher score first). An higher score means that the match is better. For
|
|
3053
|
+
* example, consecutive letters are considered a better match.
|
|
3054
|
+
*/
|
|
3055
|
+
function fuzzyLookup(pattern, list, fn) {
|
|
3056
|
+
const results = [];
|
|
3057
|
+
list.forEach((data) => {
|
|
3058
|
+
const score = fuzzyMatch(pattern, fn(data));
|
|
3059
|
+
if (score > 0) {
|
|
3060
|
+
results.push({ score, elem: data });
|
|
3061
|
+
}
|
|
3062
|
+
});
|
|
3063
|
+
// we want better matches first
|
|
3064
|
+
results.sort((a, b) => b.score - a.score);
|
|
3065
|
+
return results.map((r) => r.elem);
|
|
3066
|
+
}
|
|
3067
|
+
|
|
3068
|
+
function createDefaultRows(rowNumber) {
|
|
3069
|
+
const rows = [];
|
|
3070
|
+
for (let i = 0; i < rowNumber; i++) {
|
|
3071
|
+
const row = {
|
|
3072
|
+
cells: {},
|
|
3073
|
+
};
|
|
3074
|
+
rows.push(row);
|
|
3075
|
+
}
|
|
3076
|
+
return rows;
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
/*
|
|
3080
|
+
* https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
|
|
3081
|
+
* */
|
|
3082
|
+
class UuidGenerator {
|
|
3083
|
+
isFastIdStrategy = false;
|
|
3084
|
+
fastIdStart = 0;
|
|
3085
|
+
setIsFastStrategy(isFast) {
|
|
3086
|
+
this.isFastIdStrategy = isFast;
|
|
3087
|
+
}
|
|
3088
|
+
uuidv4() {
|
|
3089
|
+
if (this.isFastIdStrategy) {
|
|
3090
|
+
this.fastIdStart++;
|
|
3091
|
+
return String(this.fastIdStart);
|
|
3092
|
+
//@ts-ignore
|
|
3093
|
+
}
|
|
3094
|
+
else if (window.crypto && window.crypto.getRandomValues) {
|
|
3095
|
+
//@ts-ignore
|
|
3096
|
+
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16));
|
|
3097
|
+
}
|
|
3098
|
+
else {
|
|
3099
|
+
// mainly for jest and other browsers that do not have the crypto functionality
|
|
3100
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
3101
|
+
var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
|
|
3102
|
+
return v.toString(16);
|
|
3103
|
+
});
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
|
|
3070
3108
|
class ChartJsComponent extends owl.Component {
|
|
3071
3109
|
static template = "o-spreadsheet-ChartJsComponent";
|
|
3072
3110
|
canvas = owl.useRef("graphContainer");
|
|
@@ -5184,14 +5222,6 @@ function* iterateChildren(el) {
|
|
|
5184
5222
|
}
|
|
5185
5223
|
}
|
|
5186
5224
|
}
|
|
5187
|
-
function getElementScrollTop(el) {
|
|
5188
|
-
return el?.scrollTop || 0;
|
|
5189
|
-
}
|
|
5190
|
-
function setElementScrollTop(el, scroll) {
|
|
5191
|
-
if (!el)
|
|
5192
|
-
return;
|
|
5193
|
-
el.scrollTop = scroll;
|
|
5194
|
-
}
|
|
5195
5225
|
function getOpenedMenus() {
|
|
5196
5226
|
return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
|
|
5197
5227
|
}
|
|
@@ -17646,50 +17676,51 @@ const uuidGenerator$1 = new UuidGenerator();
|
|
|
17646
17676
|
css /* scss */ `
|
|
17647
17677
|
.o-selection {
|
|
17648
17678
|
.o-selection-input {
|
|
17649
|
-
|
|
17650
|
-
flex-direction: row;
|
|
17679
|
+
padding: 2px 0px;
|
|
17651
17680
|
|
|
17652
17681
|
input {
|
|
17653
17682
|
padding: 4px 6px;
|
|
17654
17683
|
border-radius: 4px;
|
|
17655
17684
|
box-sizing: border-box;
|
|
17656
|
-
flex-grow: 2;
|
|
17657
17685
|
}
|
|
17658
17686
|
input:focus {
|
|
17659
17687
|
outline: none;
|
|
17660
17688
|
}
|
|
17661
17689
|
input.o-required,
|
|
17662
17690
|
input.o-focused {
|
|
17663
|
-
border
|
|
17664
|
-
padding: 3px 5px;
|
|
17691
|
+
border: 1px solid;
|
|
17665
17692
|
}
|
|
17666
17693
|
input.o-focused {
|
|
17667
|
-
border-
|
|
17694
|
+
border-width: 2px;
|
|
17695
|
+
padding: 3px 5px;
|
|
17668
17696
|
}
|
|
17669
17697
|
input.o-invalid {
|
|
17670
|
-
|
|
17698
|
+
/* The background-color is similar to the bootstrap alert-danger class but, because of the commit 0358a76d,
|
|
17699
|
+
* which avoids being parasitized by the dark-mode in spreadsheet, we cannot use this class.
|
|
17700
|
+
* TODO: Replace with the bootstrap alert-danger class when we support dark mode
|
|
17701
|
+
*/
|
|
17702
|
+
background-color: #ffdddd;
|
|
17703
|
+
border-width: 2px;
|
|
17671
17704
|
}
|
|
17672
17705
|
button.o-btn {
|
|
17673
|
-
background: transparent;
|
|
17674
|
-
border: none;
|
|
17675
17706
|
color: #333;
|
|
17676
|
-
cursor: pointer;
|
|
17677
17707
|
}
|
|
17678
17708
|
button.o-btn-action {
|
|
17679
17709
|
margin: 8px 1px;
|
|
17680
17710
|
border-radius: 4px;
|
|
17681
|
-
background: transparent;
|
|
17682
17711
|
border: 1px solid #dadce0;
|
|
17683
17712
|
color: #188038;
|
|
17684
|
-
font-weight: bold;
|
|
17685
17713
|
font-size: 14px;
|
|
17686
17714
|
height: 25px;
|
|
17687
17715
|
}
|
|
17716
|
+
.error-icon {
|
|
17717
|
+
right: 7px;
|
|
17718
|
+
top: 7px;
|
|
17719
|
+
}
|
|
17688
17720
|
}
|
|
17689
17721
|
/** Make the character a bit bigger
|
|
17690
17722
|
compared to its neighbor INPUT box */
|
|
17691
17723
|
.o-remove-selection {
|
|
17692
|
-
font-weight: bold;
|
|
17693
17724
|
font-size: calc(100% + 4px);
|
|
17694
17725
|
}
|
|
17695
17726
|
}
|
|
@@ -17705,7 +17736,7 @@ css /* scss */ `
|
|
|
17705
17736
|
class SelectionInput extends owl.Component {
|
|
17706
17737
|
static template = "o-spreadsheet-SelectionInput";
|
|
17707
17738
|
id = uuidGenerator$1.uuidv4();
|
|
17708
|
-
previousRanges = this.props.ranges || [];
|
|
17739
|
+
previousRanges = this.props.ranges() || [];
|
|
17709
17740
|
originSheet = this.env.model.getters.getActiveSheetId();
|
|
17710
17741
|
state = owl.useState({
|
|
17711
17742
|
isMissing: false,
|
|
@@ -17713,11 +17744,11 @@ class SelectionInput extends owl.Component {
|
|
|
17713
17744
|
});
|
|
17714
17745
|
focusedInput = owl.useRef("focusedInput");
|
|
17715
17746
|
get ranges() {
|
|
17716
|
-
const
|
|
17717
|
-
const ranges =
|
|
17718
|
-
?
|
|
17719
|
-
: this.props.ranges
|
|
17720
|
-
? this.props.ranges.map((xc, id) => ({
|
|
17747
|
+
const existingSelectionRanges = this.env.model.getters.getSelectionInput(this.id);
|
|
17748
|
+
const ranges = existingSelectionRanges.length
|
|
17749
|
+
? existingSelectionRanges
|
|
17750
|
+
: this.props.ranges()
|
|
17751
|
+
? this.props.ranges().map((xc, id) => ({
|
|
17721
17752
|
xc,
|
|
17722
17753
|
id,
|
|
17723
17754
|
isFocused: false,
|
|
@@ -17737,6 +17768,12 @@ class SelectionInput extends owl.Component {
|
|
|
17737
17768
|
get isInvalid() {
|
|
17738
17769
|
return this.props.isInvalid || this.state.isMissing;
|
|
17739
17770
|
}
|
|
17771
|
+
get isConfirmable() {
|
|
17772
|
+
return this.hasFocus && this.ranges.every((range) => range.isValidRange);
|
|
17773
|
+
}
|
|
17774
|
+
get isResettable() {
|
|
17775
|
+
return this.previousRanges.join() !== this.ranges.map((r) => r.xc).join();
|
|
17776
|
+
}
|
|
17740
17777
|
setup() {
|
|
17741
17778
|
owl.useEffect(() => this.focusedInput.el?.focus(), () => [this.focusedInput.el]);
|
|
17742
17779
|
owl.onMounted(() => this.enableNewSelectionInput());
|
|
@@ -17746,7 +17783,7 @@ class SelectionInput extends owl.Component {
|
|
|
17746
17783
|
enableNewSelectionInput() {
|
|
17747
17784
|
this.env.model.dispatch("ENABLE_NEW_SELECTION_INPUT", {
|
|
17748
17785
|
id: this.id,
|
|
17749
|
-
initialRanges: this.props.ranges,
|
|
17786
|
+
initialRanges: this.props.ranges(),
|
|
17750
17787
|
hasSingleRange: this.props.hasSingleRange,
|
|
17751
17788
|
});
|
|
17752
17789
|
}
|
|
@@ -17755,7 +17792,8 @@ class SelectionInput extends owl.Component {
|
|
|
17755
17792
|
}
|
|
17756
17793
|
checkChange() {
|
|
17757
17794
|
const value = this.env.model.getters.getSelectionInputValue(this.id);
|
|
17758
|
-
|
|
17795
|
+
const valid = !this.isInvalid && this.ranges.every((range) => range.isValidRange);
|
|
17796
|
+
if (valid && this.previousRanges.join() !== value.join()) {
|
|
17759
17797
|
this.triggerChange();
|
|
17760
17798
|
}
|
|
17761
17799
|
}
|
|
@@ -17766,7 +17804,6 @@ class SelectionInput extends owl.Component {
|
|
|
17766
17804
|
triggerChange() {
|
|
17767
17805
|
const ranges = this.env.model.getters.getSelectionInputValue(this.id);
|
|
17768
17806
|
this.props.onSelectionChanged?.(ranges);
|
|
17769
|
-
this.previousRanges = ranges;
|
|
17770
17807
|
}
|
|
17771
17808
|
onKeydown(ev) {
|
|
17772
17809
|
if (ev.key === "F2") {
|
|
@@ -17816,10 +17853,37 @@ class SelectionInput extends owl.Component {
|
|
|
17816
17853
|
});
|
|
17817
17854
|
this.triggerChange();
|
|
17818
17855
|
}
|
|
17856
|
+
reset() {
|
|
17857
|
+
const existingSelectionRanges = this.env.model.getters.getSelectionInput(this.id);
|
|
17858
|
+
for (const range of existingSelectionRanges) {
|
|
17859
|
+
this.env.model.dispatch("REMOVE_RANGE", {
|
|
17860
|
+
id: this.id,
|
|
17861
|
+
rangeId: range.id,
|
|
17862
|
+
});
|
|
17863
|
+
}
|
|
17864
|
+
for (const range of this.previousRanges) {
|
|
17865
|
+
this.env.model.dispatch("ADD_RANGE", { id: this.id, value: range });
|
|
17866
|
+
}
|
|
17867
|
+
this.confirm();
|
|
17868
|
+
}
|
|
17819
17869
|
confirm() {
|
|
17820
|
-
|
|
17821
|
-
const
|
|
17822
|
-
|
|
17870
|
+
let anyValidInput = false;
|
|
17871
|
+
const existingSelectionRanges = this.env.model.getters.getSelectionInput(this.id);
|
|
17872
|
+
const existingSelectionXcs = [];
|
|
17873
|
+
for (const range of existingSelectionRanges) {
|
|
17874
|
+
if (range.xc === "") {
|
|
17875
|
+
this.env.model.dispatch("REMOVE_RANGE", {
|
|
17876
|
+
id: this.id,
|
|
17877
|
+
rangeId: range.id,
|
|
17878
|
+
});
|
|
17879
|
+
continue;
|
|
17880
|
+
}
|
|
17881
|
+
existingSelectionXcs.push(range.xc);
|
|
17882
|
+
if (this.env.model.getters.isRangeValid(range.xc)) {
|
|
17883
|
+
anyValidInput = true;
|
|
17884
|
+
}
|
|
17885
|
+
}
|
|
17886
|
+
if (this.props.required && !anyValidInput) {
|
|
17823
17887
|
this.state.isMissing = true;
|
|
17824
17888
|
}
|
|
17825
17889
|
const activeSheetId = this.env.model.getters.getActiveSheetId();
|
|
@@ -17829,11 +17893,17 @@ class SelectionInput extends owl.Component {
|
|
|
17829
17893
|
sheetIdTo: this.originSheet,
|
|
17830
17894
|
});
|
|
17831
17895
|
}
|
|
17896
|
+
this.props.onSelectionChanged?.(existingSelectionXcs);
|
|
17832
17897
|
this.props.onSelectionConfirmed?.();
|
|
17898
|
+
this.previousRanges = this.props.ranges();
|
|
17899
|
+
if (existingSelectionXcs.join() !== this.previousRanges.join()) {
|
|
17900
|
+
this.enableNewSelectionInput();
|
|
17901
|
+
}
|
|
17902
|
+
this.env.model.dispatch("UNFOCUS_SELECTION_INPUT");
|
|
17833
17903
|
}
|
|
17834
17904
|
}
|
|
17835
17905
|
SelectionInput.props = {
|
|
17836
|
-
ranges:
|
|
17906
|
+
ranges: Function,
|
|
17837
17907
|
hasSingleRange: { type: Boolean, optional: true },
|
|
17838
17908
|
required: { type: Boolean, optional: true },
|
|
17839
17909
|
isInvalid: { type: Boolean, optional: true },
|
|
@@ -17869,7 +17939,7 @@ class LineBarPieConfigPanel extends owl.Component {
|
|
|
17869
17939
|
return !!this.state.labelsDispatchResult?.isCancelledBecause(33 /* CommandResult.InvalidLabelRange */);
|
|
17870
17940
|
}
|
|
17871
17941
|
onUpdateDataSetsHaveTitle(ev) {
|
|
17872
|
-
this.props.updateChart({
|
|
17942
|
+
this.props.updateChart(this.props.figureId, {
|
|
17873
17943
|
dataSetsHaveTitle: ev.target.checked,
|
|
17874
17944
|
});
|
|
17875
17945
|
}
|
|
@@ -17881,10 +17951,14 @@ class LineBarPieConfigPanel extends owl.Component {
|
|
|
17881
17951
|
this.dataSeriesRanges = ranges;
|
|
17882
17952
|
}
|
|
17883
17953
|
onDataSeriesConfirmed() {
|
|
17884
|
-
this.
|
|
17954
|
+
this.dataSeriesRanges = spreadRange(this.dataSeriesRanges);
|
|
17955
|
+
this.state.datasetDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
17885
17956
|
dataSets: this.dataSeriesRanges,
|
|
17886
17957
|
});
|
|
17887
17958
|
}
|
|
17959
|
+
getDataSeriesRanges() {
|
|
17960
|
+
return this.dataSeriesRanges;
|
|
17961
|
+
}
|
|
17888
17962
|
/**
|
|
17889
17963
|
* Change the local labelRange. The model should be updated when the
|
|
17890
17964
|
* button "confirm" is clicked
|
|
@@ -17893,12 +17967,15 @@ class LineBarPieConfigPanel extends owl.Component {
|
|
|
17893
17967
|
this.labelRange = ranges[0];
|
|
17894
17968
|
}
|
|
17895
17969
|
onLabelRangeConfirmed() {
|
|
17896
|
-
this.state.labelsDispatchResult = this.props.updateChart({
|
|
17970
|
+
this.state.labelsDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
17897
17971
|
labelRange: this.labelRange,
|
|
17898
17972
|
});
|
|
17899
17973
|
}
|
|
17974
|
+
getLabelRange() {
|
|
17975
|
+
return this.labelRange || "";
|
|
17976
|
+
}
|
|
17900
17977
|
onUpdateAggregated(ev) {
|
|
17901
|
-
this.props.updateChart({
|
|
17978
|
+
this.props.updateChart(this.props.figureId, {
|
|
17902
17979
|
aggregated: ev.target.checked,
|
|
17903
17980
|
});
|
|
17904
17981
|
}
|
|
@@ -17928,12 +18005,12 @@ LineBarPieConfigPanel.props = {
|
|
|
17928
18005
|
class BarConfigPanel extends LineBarPieConfigPanel {
|
|
17929
18006
|
static template = "o-spreadsheet-BarConfigPanel";
|
|
17930
18007
|
onUpdateStacked(ev) {
|
|
17931
|
-
this.props.updateChart({
|
|
18008
|
+
this.props.updateChart(this.props.figureId, {
|
|
17932
18009
|
stacked: ev.target.checked,
|
|
17933
18010
|
});
|
|
17934
18011
|
}
|
|
17935
18012
|
onUpdateAggregated(ev) {
|
|
17936
|
-
this.props.updateChart({
|
|
18013
|
+
this.props.updateChart(this.props.figureId, {
|
|
17937
18014
|
aggregated: ev.target.checked,
|
|
17938
18015
|
});
|
|
17939
18016
|
}
|
|
@@ -18270,17 +18347,17 @@ class LineBarPieDesignPanel extends owl.Component {
|
|
|
18270
18347
|
this.state.fillColorTool = !this.state.fillColorTool;
|
|
18271
18348
|
}
|
|
18272
18349
|
updateBackgroundColor(color) {
|
|
18273
|
-
this.props.updateChart({
|
|
18350
|
+
this.props.updateChart(this.props.figureId, {
|
|
18274
18351
|
background: color,
|
|
18275
18352
|
});
|
|
18276
18353
|
}
|
|
18277
18354
|
updateTitle(ev) {
|
|
18278
|
-
this.props.updateChart({
|
|
18355
|
+
this.props.updateChart(this.props.figureId, {
|
|
18279
18356
|
title: ev.target.value,
|
|
18280
18357
|
});
|
|
18281
18358
|
}
|
|
18282
18359
|
updateSelect(attr, ev) {
|
|
18283
|
-
this.props.updateChart({
|
|
18360
|
+
this.props.updateChart(this.props.figureId, {
|
|
18284
18361
|
[attr]: ev.target.value,
|
|
18285
18362
|
});
|
|
18286
18363
|
}
|
|
@@ -18313,10 +18390,13 @@ class GaugeChartConfigPanel extends owl.Component {
|
|
|
18313
18390
|
this.dataRange = ranges[0];
|
|
18314
18391
|
}
|
|
18315
18392
|
updateDataRange() {
|
|
18316
|
-
this.state.dataRangeDispatchResult = this.props.updateChart({
|
|
18393
|
+
this.state.dataRangeDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
18317
18394
|
dataRange: this.dataRange,
|
|
18318
18395
|
});
|
|
18319
18396
|
}
|
|
18397
|
+
getDataRange() {
|
|
18398
|
+
return this.dataRange || "";
|
|
18399
|
+
}
|
|
18320
18400
|
}
|
|
18321
18401
|
GaugeChartConfigPanel.props = {
|
|
18322
18402
|
figureId: String,
|
|
@@ -18371,12 +18451,12 @@ class GaugeChartDesignPanel extends owl.Component {
|
|
|
18371
18451
|
}
|
|
18372
18452
|
updateBackgroundColor(color) {
|
|
18373
18453
|
this.state.openedMenu = undefined;
|
|
18374
|
-
this.props.updateChart({
|
|
18454
|
+
this.props.updateChart(this.props.figureId, {
|
|
18375
18455
|
background: color,
|
|
18376
18456
|
});
|
|
18377
18457
|
}
|
|
18378
18458
|
updateTitle(ev) {
|
|
18379
|
-
this.props.updateChart({
|
|
18459
|
+
this.props.updateChart(this.props.figureId, {
|
|
18380
18460
|
title: ev.target.value,
|
|
18381
18461
|
});
|
|
18382
18462
|
}
|
|
@@ -18441,7 +18521,7 @@ class GaugeChartDesignPanel extends owl.Component {
|
|
|
18441
18521
|
}
|
|
18442
18522
|
}
|
|
18443
18523
|
updateSectionRule(sectionRule) {
|
|
18444
|
-
this.state.sectionRuleDispatchResult = this.props.updateChart({
|
|
18524
|
+
this.state.sectionRuleDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
18445
18525
|
sectionRule,
|
|
18446
18526
|
});
|
|
18447
18527
|
}
|
|
@@ -18465,17 +18545,17 @@ class LineConfigPanel extends LineBarPieConfigPanel {
|
|
|
18465
18545
|
return false;
|
|
18466
18546
|
}
|
|
18467
18547
|
onUpdateLabelsAsText(ev) {
|
|
18468
|
-
this.props.updateChart({
|
|
18548
|
+
this.props.updateChart(this.props.figureId, {
|
|
18469
18549
|
labelsAsText: ev.target.checked,
|
|
18470
18550
|
});
|
|
18471
18551
|
}
|
|
18472
18552
|
onUpdateStacked(ev) {
|
|
18473
|
-
this.props.updateChart({
|
|
18553
|
+
this.props.updateChart(this.props.figureId, {
|
|
18474
18554
|
stacked: ev.target.checked,
|
|
18475
18555
|
});
|
|
18476
18556
|
}
|
|
18477
18557
|
onUpdateAggregated(ev) {
|
|
18478
|
-
this.props.updateChart({
|
|
18558
|
+
this.props.updateChart(this.props.figureId, {
|
|
18479
18559
|
aggregated: ev.target.checked,
|
|
18480
18560
|
});
|
|
18481
18561
|
}
|
|
@@ -18511,20 +18591,26 @@ class ScorecardChartConfigPanel extends owl.Component {
|
|
|
18511
18591
|
this.keyValue = ranges[0];
|
|
18512
18592
|
}
|
|
18513
18593
|
updateKeyValueRange() {
|
|
18514
|
-
this.state.keyValueDispatchResult = this.props.updateChart({
|
|
18594
|
+
this.state.keyValueDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
18515
18595
|
keyValue: this.keyValue,
|
|
18516
18596
|
});
|
|
18517
18597
|
}
|
|
18598
|
+
getKeyValueRange() {
|
|
18599
|
+
return this.keyValue || "";
|
|
18600
|
+
}
|
|
18518
18601
|
onBaselineRangeChanged(ranges) {
|
|
18519
18602
|
this.baseline = ranges[0];
|
|
18520
18603
|
}
|
|
18521
18604
|
updateBaselineRange() {
|
|
18522
|
-
this.state.baselineDispatchResult = this.props.updateChart({
|
|
18605
|
+
this.state.baselineDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
18523
18606
|
baseline: this.baseline,
|
|
18524
18607
|
});
|
|
18525
18608
|
}
|
|
18609
|
+
getBaselineRange() {
|
|
18610
|
+
return this.baseline || "";
|
|
18611
|
+
}
|
|
18526
18612
|
updateBaselineMode(ev) {
|
|
18527
|
-
this.props.updateChart({ baselineMode: ev.target.value });
|
|
18613
|
+
this.props.updateChart(this.props.figureId, { baselineMode: ev.target.value });
|
|
18528
18614
|
}
|
|
18529
18615
|
}
|
|
18530
18616
|
ScorecardChartConfigPanel.props = {
|
|
@@ -18543,12 +18629,12 @@ class ScorecardChartDesignPanel extends owl.Component {
|
|
|
18543
18629
|
owl.useExternalListener(window, "click", this.closeMenus);
|
|
18544
18630
|
}
|
|
18545
18631
|
updateTitle(ev) {
|
|
18546
|
-
this.props.updateChart({
|
|
18632
|
+
this.props.updateChart(this.props.figureId, {
|
|
18547
18633
|
title: ev.target.value,
|
|
18548
18634
|
});
|
|
18549
18635
|
}
|
|
18550
18636
|
updateBaselineDescr(ev) {
|
|
18551
|
-
this.props.updateChart({ baselineDescr: ev.target.value });
|
|
18637
|
+
this.props.updateChart(this.props.figureId, { baselineDescr: ev.target.value });
|
|
18552
18638
|
}
|
|
18553
18639
|
toggleColorPicker(colorPickerId) {
|
|
18554
18640
|
if (this.state.openedColorPicker === colorPickerId) {
|
|
@@ -18561,13 +18647,13 @@ class ScorecardChartDesignPanel extends owl.Component {
|
|
|
18561
18647
|
setColor(color, colorPickerId) {
|
|
18562
18648
|
switch (colorPickerId) {
|
|
18563
18649
|
case "backgroundColor":
|
|
18564
|
-
this.props.updateChart({ background: color });
|
|
18650
|
+
this.props.updateChart(this.props.figureId, { background: color });
|
|
18565
18651
|
break;
|
|
18566
18652
|
case "baselineColorDown":
|
|
18567
|
-
this.props.updateChart({ baselineColorDown: color });
|
|
18653
|
+
this.props.updateChart(this.props.figureId, { baselineColorDown: color });
|
|
18568
18654
|
break;
|
|
18569
18655
|
case "baselineColorUp":
|
|
18570
|
-
this.props.updateChart({ baselineColorUp: color });
|
|
18656
|
+
this.props.updateChart(this.props.figureId, { baselineColorUp: color });
|
|
18571
18657
|
break;
|
|
18572
18658
|
}
|
|
18573
18659
|
this.closeMenus();
|
|
@@ -18632,13 +18718,9 @@ css /* scss */ `
|
|
|
18632
18718
|
class ChartPanel extends owl.Component {
|
|
18633
18719
|
static template = "o-spreadsheet-ChartPanel";
|
|
18634
18720
|
state;
|
|
18635
|
-
shouldUpdateChart = true;
|
|
18636
18721
|
get figureId() {
|
|
18637
18722
|
return this.state.figureId;
|
|
18638
18723
|
}
|
|
18639
|
-
get sheetId() {
|
|
18640
|
-
return this.state.sheetId;
|
|
18641
|
-
}
|
|
18642
18724
|
setup() {
|
|
18643
18725
|
const selectedFigureId = this.env.model.getters.getSelectedFigureId();
|
|
18644
18726
|
if (!selectedFigureId) {
|
|
@@ -18648,17 +18730,11 @@ class ChartPanel extends owl.Component {
|
|
|
18648
18730
|
this.state = owl.useState({
|
|
18649
18731
|
panel: "configuration",
|
|
18650
18732
|
figureId: selectedFigureId,
|
|
18651
|
-
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
18652
18733
|
});
|
|
18653
18734
|
owl.onWillUpdateProps(() => {
|
|
18654
18735
|
const selectedFigureId = this.env.model.getters.getSelectedFigureId();
|
|
18655
18736
|
if (selectedFigureId && selectedFigureId !== this.state.figureId) {
|
|
18656
18737
|
this.state.figureId = selectedFigureId;
|
|
18657
|
-
this.state.sheetId = this.env.model.getters.getActiveSheetId();
|
|
18658
|
-
this.shouldUpdateChart = false;
|
|
18659
|
-
}
|
|
18660
|
-
else {
|
|
18661
|
-
this.shouldUpdateChart = true;
|
|
18662
18738
|
}
|
|
18663
18739
|
if (!this.env.model.getters.isChartDefined(this.figureId)) {
|
|
18664
18740
|
this.props.onCloseSidePanel();
|
|
@@ -18666,8 +18742,8 @@ class ChartPanel extends owl.Component {
|
|
|
18666
18742
|
}
|
|
18667
18743
|
});
|
|
18668
18744
|
}
|
|
18669
|
-
updateChart(updateDefinition) {
|
|
18670
|
-
if (
|
|
18745
|
+
updateChart(figureId, updateDefinition) {
|
|
18746
|
+
if (figureId !== this.figureId) {
|
|
18671
18747
|
return;
|
|
18672
18748
|
}
|
|
18673
18749
|
const definition = {
|
|
@@ -18676,8 +18752,8 @@ class ChartPanel extends owl.Component {
|
|
|
18676
18752
|
};
|
|
18677
18753
|
return this.env.model.dispatch("UPDATE_CHART", {
|
|
18678
18754
|
definition,
|
|
18679
|
-
id:
|
|
18680
|
-
sheetId: this.
|
|
18755
|
+
id: figureId,
|
|
18756
|
+
sheetId: this.env.model.getters.getFigureSheetId(figureId),
|
|
18681
18757
|
});
|
|
18682
18758
|
}
|
|
18683
18759
|
onTypeChange(type) {
|
|
@@ -18689,7 +18765,7 @@ class ChartPanel extends owl.Component {
|
|
|
18689
18765
|
this.env.model.dispatch("UPDATE_CHART", {
|
|
18690
18766
|
definition,
|
|
18691
18767
|
id: this.figureId,
|
|
18692
|
-
sheetId: this.
|
|
18768
|
+
sheetId: this.env.model.getters.getFigureSheetId(this.figureId),
|
|
18693
18769
|
});
|
|
18694
18770
|
}
|
|
18695
18771
|
get chartPanel() {
|
|
@@ -20485,12 +20561,23 @@ class ContentEditableHelper {
|
|
|
20485
20561
|
*/
|
|
20486
20562
|
selectRange(start, end) {
|
|
20487
20563
|
let selection = window.getSelection();
|
|
20488
|
-
this.
|
|
20489
|
-
|
|
20564
|
+
const { start: currentStart, end: currentEnd } = this.getCurrentSelection();
|
|
20565
|
+
if (currentStart === start && currentEnd === end) {
|
|
20566
|
+
return;
|
|
20567
|
+
}
|
|
20568
|
+
const currentRange = selection.getRangeAt(0);
|
|
20569
|
+
let range;
|
|
20570
|
+
if (this.el.contains(currentRange.startContainer)) {
|
|
20571
|
+
range = currentRange;
|
|
20572
|
+
}
|
|
20573
|
+
else {
|
|
20574
|
+
range = document.createRange();
|
|
20575
|
+
selection.removeAllRanges();
|
|
20576
|
+
selection.addRange(range);
|
|
20577
|
+
}
|
|
20490
20578
|
if (start == end && start === 0) {
|
|
20491
20579
|
range.setStart(this.el, 0);
|
|
20492
20580
|
range.setEnd(this.el, 0);
|
|
20493
|
-
selection.addRange(range);
|
|
20494
20581
|
}
|
|
20495
20582
|
else {
|
|
20496
20583
|
const textLength = this.getText().length;
|
|
@@ -20506,7 +20593,6 @@ class ContentEditableHelper {
|
|
|
20506
20593
|
let startNode = this.findChildAtCharacterIndex(start);
|
|
20507
20594
|
let endNode = this.findChildAtCharacterIndex(end);
|
|
20508
20595
|
range.setStart(startNode.node, startNode.offset);
|
|
20509
|
-
selection.addRange(range);
|
|
20510
20596
|
selection.extend(endNode.node, endNode.offset);
|
|
20511
20597
|
}
|
|
20512
20598
|
}
|
|
@@ -20546,26 +20632,54 @@ class ContentEditableHelper {
|
|
|
20546
20632
|
return { node: previous, offset: usedCharacters };
|
|
20547
20633
|
}
|
|
20548
20634
|
/**
|
|
20549
|
-
* Sets (or Replaces all) the text inside the root element in the form of distinctive
|
|
20635
|
+
* Sets (or Replaces all) the text inside the root element in the form of distinctive paragraphs and
|
|
20550
20636
|
* span for each element provided in `contents`.
|
|
20551
20637
|
*
|
|
20638
|
+
* The function will apply the diff between the current content and the new content to avoid the systematic
|
|
20639
|
+
* destruction of DOM elements which interferes with IME[1]
|
|
20640
|
+
*
|
|
20641
|
+
* Each line of text will be encapsulated in a paragraph element.
|
|
20552
20642
|
* Each span will have its own fontcolor and specific class if provided in the HtmlContent object.
|
|
20643
|
+
*
|
|
20644
|
+
* [1] https://developer.mozilla.org/en-US/docs/Glossary/Input_method_editor
|
|
20553
20645
|
*/
|
|
20554
20646
|
setText(contents) {
|
|
20555
|
-
this.el.innerHTML = "";
|
|
20556
20647
|
if (contents.length === 0) {
|
|
20648
|
+
this.removeAll();
|
|
20557
20649
|
return;
|
|
20558
20650
|
}
|
|
20559
|
-
|
|
20560
|
-
|
|
20561
|
-
|
|
20562
|
-
|
|
20563
|
-
|
|
20564
|
-
|
|
20565
|
-
|
|
20651
|
+
const childElements = Array.from(this.el.childNodes);
|
|
20652
|
+
const contentLength = contents.length;
|
|
20653
|
+
for (let i = 0; i < contentLength; i++) {
|
|
20654
|
+
const line = contents[i];
|
|
20655
|
+
const childElement = childElements[i];
|
|
20656
|
+
let newChild = false;
|
|
20657
|
+
let p;
|
|
20658
|
+
if (childElement && childElement.nodeName === "P") {
|
|
20659
|
+
p = childElement;
|
|
20566
20660
|
}
|
|
20567
|
-
|
|
20661
|
+
else {
|
|
20662
|
+
newChild = true;
|
|
20663
|
+
p = document.createElement("p");
|
|
20664
|
+
}
|
|
20665
|
+
const lineLength = line.length;
|
|
20666
|
+
const existingChildren = Array.from(p.childNodes);
|
|
20667
|
+
for (let j = 0; j < lineLength; j++) {
|
|
20668
|
+
const content = line[j];
|
|
20669
|
+
const child = existingChildren[j];
|
|
20670
|
+
// child nodes can be multiple types of nodes: Span, Text, Div, etc...
|
|
20671
|
+
// We can only modify a node in place if it has the same type as the content
|
|
20672
|
+
// that we would insert, which are spans.
|
|
20673
|
+
// Otherwise, it means that the node has been input by the user, through the keyboard or a copy/paste
|
|
20674
|
+
// @ts-ignore (somehow required because jest does not like child.tagName despite the prior check)
|
|
20675
|
+
const childIsSpan = child && "tagName" in child && child.tagName === "SPAN";
|
|
20676
|
+
if (childIsSpan && compareContentToSpanElement(content, child)) {
|
|
20677
|
+
continue;
|
|
20678
|
+
}
|
|
20679
|
+
// this is an empty line in the content
|
|
20568
20680
|
if (!content.value && !content.class) {
|
|
20681
|
+
if (child)
|
|
20682
|
+
p.removeChild(child);
|
|
20569
20683
|
continue;
|
|
20570
20684
|
}
|
|
20571
20685
|
const span = document.createElement("span");
|
|
@@ -20574,9 +20688,38 @@ class ContentEditableHelper {
|
|
|
20574
20688
|
if (content.class) {
|
|
20575
20689
|
span.classList.add(content.class);
|
|
20576
20690
|
}
|
|
20691
|
+
if (child) {
|
|
20692
|
+
p.replaceChild(span, child);
|
|
20693
|
+
}
|
|
20694
|
+
else {
|
|
20695
|
+
p.appendChild(span);
|
|
20696
|
+
}
|
|
20697
|
+
}
|
|
20698
|
+
if (existingChildren.length > lineLength) {
|
|
20699
|
+
for (let i = lineLength; i < existingChildren.length; i++) {
|
|
20700
|
+
p.removeChild(existingChildren[i]);
|
|
20701
|
+
}
|
|
20702
|
+
}
|
|
20703
|
+
// Empty line
|
|
20704
|
+
if (!p.hasChildNodes()) {
|
|
20705
|
+
const span = document.createElement("span");
|
|
20706
|
+
span.appendChild(document.createElement("br"));
|
|
20577
20707
|
p.appendChild(span);
|
|
20578
20708
|
}
|
|
20579
|
-
|
|
20709
|
+
// replace p if necessary
|
|
20710
|
+
if (newChild) {
|
|
20711
|
+
if (childElement) {
|
|
20712
|
+
this.el.replaceChild(p, childElement);
|
|
20713
|
+
}
|
|
20714
|
+
else {
|
|
20715
|
+
this.el.appendChild(p);
|
|
20716
|
+
}
|
|
20717
|
+
}
|
|
20718
|
+
}
|
|
20719
|
+
if (childElements.length > contentLength) {
|
|
20720
|
+
for (let i = contentLength; i < childElements.length; i++) {
|
|
20721
|
+
this.el.removeChild(childElements[i]);
|
|
20722
|
+
}
|
|
20580
20723
|
}
|
|
20581
20724
|
}
|
|
20582
20725
|
scrollSelectionIntoView() {
|
|
@@ -20586,13 +20729,6 @@ class ContentEditableHelper {
|
|
|
20586
20729
|
const element = focusedNode instanceof HTMLElement ? focusedNode : focusedNode.parentElement;
|
|
20587
20730
|
element?.scrollIntoView({ block: "nearest" });
|
|
20588
20731
|
}
|
|
20589
|
-
/**
|
|
20590
|
-
* remove the current selection of the user
|
|
20591
|
-
* */
|
|
20592
|
-
removeSelection() {
|
|
20593
|
-
let selection = window.getSelection();
|
|
20594
|
-
selection.removeAllRanges();
|
|
20595
|
-
}
|
|
20596
20732
|
removeAll() {
|
|
20597
20733
|
if (this.el) {
|
|
20598
20734
|
while (this.el.firstChild) {
|
|
@@ -20722,6 +20858,14 @@ class ContentEditableHelper {
|
|
|
20722
20858
|
}
|
|
20723
20859
|
return text;
|
|
20724
20860
|
}
|
|
20861
|
+
}
|
|
20862
|
+
function compareContentToSpanElement(content, node) {
|
|
20863
|
+
const contentColor = content.color ? toHex(content.color) : "";
|
|
20864
|
+
const nodeColor = node.style?.color ? toHex(node.style.color) : "";
|
|
20865
|
+
const sameColor = contentColor === nodeColor;
|
|
20866
|
+
const sameClass = deepEquals([content.class], [...node.classList]);
|
|
20867
|
+
const sameContent = node.innerText === content.value;
|
|
20868
|
+
return sameColor && sameClass && sameContent;
|
|
20725
20869
|
}
|
|
20726
20870
|
|
|
20727
20871
|
// -----------------------------------------------------------------------------
|
|
@@ -20867,7 +21011,6 @@ class Composer extends owl.Component {
|
|
|
20867
21011
|
functionDescription: {},
|
|
20868
21012
|
argToFocus: 0,
|
|
20869
21013
|
});
|
|
20870
|
-
isKeyStillDown = false;
|
|
20871
21014
|
compositionActive = false;
|
|
20872
21015
|
get assistantStyle() {
|
|
20873
21016
|
if (this.props.delimitation && this.props.rect) {
|
|
@@ -20902,21 +21045,18 @@ class Composer extends owl.Component {
|
|
|
20902
21045
|
F2: () => console.warn("Not implemented"),
|
|
20903
21046
|
F4: this.processF4Key,
|
|
20904
21047
|
Tab: (ev) => this.processTabKey(ev),
|
|
21048
|
+
" ": (ev) => this.processSpaceKey(ev),
|
|
20905
21049
|
};
|
|
20906
21050
|
setup() {
|
|
20907
21051
|
owl.onMounted(() => {
|
|
20908
21052
|
const el = this.composerRef.el;
|
|
20909
21053
|
this.contentHelper.updateEl(el);
|
|
20910
|
-
this.processContent();
|
|
20911
|
-
this.contentHelper.scrollSelectionIntoView();
|
|
20912
21054
|
});
|
|
20913
21055
|
owl.onWillUnmount(() => {
|
|
20914
21056
|
this.props.onComposerUnmounted?.();
|
|
20915
21057
|
});
|
|
20916
|
-
owl.
|
|
20917
|
-
|
|
20918
|
-
this.processContent();
|
|
20919
|
-
}
|
|
21058
|
+
owl.useEffect(() => {
|
|
21059
|
+
this.processContent();
|
|
20920
21060
|
});
|
|
20921
21061
|
}
|
|
20922
21062
|
// ---------------------------------------------------------------------------
|
|
@@ -20969,32 +21109,25 @@ class Composer extends owl.Component {
|
|
|
20969
21109
|
return;
|
|
20970
21110
|
}
|
|
20971
21111
|
}
|
|
20972
|
-
else {
|
|
20973
|
-
// when completing with tab, if there is no value to complete, the active cell will be moved to the right.
|
|
20974
|
-
// we can't let the model think that it is for a ref selection.
|
|
20975
|
-
// todo: check if this can be removed someday
|
|
20976
|
-
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
20977
|
-
}
|
|
20978
21112
|
const direction = ev.shiftKey ? "left" : "right";
|
|
20979
21113
|
this.env.model.dispatch("STOP_EDITION");
|
|
20980
21114
|
this.env.model.selection.moveAnchorCell(direction, 1);
|
|
20981
21115
|
}
|
|
21116
|
+
processSpaceKey(ev) {
|
|
21117
|
+
if (ev.ctrlKey) {
|
|
21118
|
+
ev.preventDefault();
|
|
21119
|
+
ev.stopPropagation();
|
|
21120
|
+
this.showAutocomplete("");
|
|
21121
|
+
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
21122
|
+
}
|
|
21123
|
+
}
|
|
20982
21124
|
processEnterKey(ev) {
|
|
20983
21125
|
ev.preventDefault();
|
|
20984
21126
|
ev.stopPropagation();
|
|
20985
21127
|
if (ev.altKey || ev.ctrlKey) {
|
|
20986
|
-
|
|
20987
|
-
const currentContent = this.env.model.getters.getCurrentContent();
|
|
20988
|
-
const content = currentContent.slice(0, selection.start) + NEWLINE + currentContent.slice(selection.end);
|
|
20989
|
-
this.env.model.dispatch("SET_CURRENT_CONTENT", {
|
|
20990
|
-
content,
|
|
20991
|
-
selection: { start: selection.start + 1, end: selection.start + 1 },
|
|
20992
|
-
});
|
|
20993
|
-
this.processContent();
|
|
20994
|
-
this.contentHelper.scrollSelectionIntoView();
|
|
21128
|
+
this.composerRef.el?.dispatchEvent(new InputEvent("input", { inputType: "insertParagraph", bubbles: true, isComposing: false }));
|
|
20995
21129
|
return;
|
|
20996
21130
|
}
|
|
20997
|
-
this.isKeyStillDown = false;
|
|
20998
21131
|
if (this.autoCompleteState.showProvider) {
|
|
20999
21132
|
const autoCompleteValue = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]?.text;
|
|
21000
21133
|
if (autoCompleteValue) {
|
|
@@ -21027,56 +21160,42 @@ class Composer extends owl.Component {
|
|
|
21027
21160
|
else {
|
|
21028
21161
|
ev.stopPropagation();
|
|
21029
21162
|
}
|
|
21030
|
-
const { start, end } = this.contentHelper.getCurrentSelection();
|
|
21031
|
-
if (!this.env.model.getters.isSelectingForComposer() &&
|
|
21032
|
-
!(ev.key === "Enter" && (ev.altKey || ev.ctrlKey))) {
|
|
21033
|
-
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", { start, end });
|
|
21034
|
-
this.isKeyStillDown = true;
|
|
21035
|
-
}
|
|
21036
21163
|
}
|
|
21037
21164
|
/*
|
|
21038
21165
|
* Triggered automatically by the content-editable between the keydown and key up
|
|
21039
21166
|
* */
|
|
21040
|
-
onInput() {
|
|
21167
|
+
onInput(ev) {
|
|
21041
21168
|
if (this.props.focus === "inactive" || !this.shouldProcessInputEvents) {
|
|
21042
21169
|
return;
|
|
21043
21170
|
}
|
|
21171
|
+
let content = this.contentHelper.getText();
|
|
21172
|
+
let selection = this.contentHelper.getCurrentSelection();
|
|
21173
|
+
if (ev.inputType === "insertParagraph") {
|
|
21174
|
+
const start = Math.min(selection.start, selection.end);
|
|
21175
|
+
const end = Math.max(selection.start, selection.end);
|
|
21176
|
+
content = content.slice(0, start) + NEWLINE + content.slice(end);
|
|
21177
|
+
selection = { start: start + 1, end: start + 1 };
|
|
21178
|
+
}
|
|
21044
21179
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
21045
21180
|
this.env.model.dispatch("SET_CURRENT_CONTENT", {
|
|
21046
|
-
content
|
|
21047
|
-
selection
|
|
21181
|
+
content,
|
|
21182
|
+
selection,
|
|
21048
21183
|
});
|
|
21184
|
+
this.processTokenAtCursor();
|
|
21049
21185
|
}
|
|
21050
|
-
onKeyup(
|
|
21051
|
-
this.
|
|
21052
|
-
|
|
21053
|
-
|
|
21054
|
-
|
|
21055
|
-
|
|
21056
|
-
|
|
21057
|
-
return; // already processed in keydown
|
|
21058
|
-
}
|
|
21059
|
-
if (this.env.model.getters.isSelectingForComposer() &&
|
|
21060
|
-
["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(ev.key)) {
|
|
21061
|
-
return; // already processed in keydown
|
|
21062
|
-
}
|
|
21063
|
-
ev.preventDefault();
|
|
21064
|
-
ev.stopPropagation();
|
|
21065
|
-
this.autoCompleteState.showProvider = false;
|
|
21066
|
-
if (ev.ctrlKey && ev.key === " ") {
|
|
21067
|
-
this.showAutocomplete("");
|
|
21068
|
-
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
21069
|
-
return;
|
|
21070
|
-
}
|
|
21071
|
-
const { start: oldStart, end: oldEnd } = this.env.model.getters.getComposerSelection();
|
|
21072
|
-
const { start, end } = this.contentHelper.getCurrentSelection();
|
|
21073
|
-
if (start !== oldStart || end !== oldEnd) {
|
|
21074
|
-
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", this.contentHelper.getCurrentSelection());
|
|
21186
|
+
onKeyup() {
|
|
21187
|
+
if (this.contentHelper.el === document.activeElement) {
|
|
21188
|
+
const { start: oldStart, end: oldEnd } = this.env.model.getters.getComposerSelection();
|
|
21189
|
+
const { start, end } = this.contentHelper.getCurrentSelection();
|
|
21190
|
+
if (start !== oldStart || end !== oldEnd) {
|
|
21191
|
+
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", { start, end });
|
|
21192
|
+
}
|
|
21075
21193
|
}
|
|
21076
|
-
this.processTokenAtCursor();
|
|
21077
|
-
this.processContent();
|
|
21078
21194
|
}
|
|
21079
21195
|
showAutocomplete(searchTerm) {
|
|
21196
|
+
if (!this.env.model.getters.getCurrentContent().startsWith("=")) {
|
|
21197
|
+
return;
|
|
21198
|
+
}
|
|
21080
21199
|
this.autoCompleteState.showProvider = true;
|
|
21081
21200
|
let values = Object.entries(functionRegistry.content)
|
|
21082
21201
|
.filter(([_, { hidden }]) => !hidden)
|
|
@@ -21096,13 +21215,6 @@ class Composer extends owl.Component {
|
|
|
21096
21215
|
this.autoCompleteState.values = values.slice(0, 10);
|
|
21097
21216
|
this.autoCompleteState.selectedIndex = 0;
|
|
21098
21217
|
}
|
|
21099
|
-
onMousedown(ev) {
|
|
21100
|
-
if (ev.button > 0) {
|
|
21101
|
-
// not main button, probably a context menu
|
|
21102
|
-
return;
|
|
21103
|
-
}
|
|
21104
|
-
this.contentHelper.removeSelection();
|
|
21105
|
-
}
|
|
21106
21218
|
onClick() {
|
|
21107
21219
|
if (this.env.model.getters.isReadonly()) {
|
|
21108
21220
|
return;
|
|
@@ -21115,9 +21227,6 @@ class Composer extends owl.Component {
|
|
|
21115
21227
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
|
|
21116
21228
|
this.processTokenAtCursor();
|
|
21117
21229
|
}
|
|
21118
|
-
onBlur() {
|
|
21119
|
-
this.isKeyStillDown = false;
|
|
21120
|
-
}
|
|
21121
21230
|
// ---------------------------------------------------------------------------
|
|
21122
21231
|
// Private
|
|
21123
21232
|
// ---------------------------------------------------------------------------
|
|
@@ -21125,22 +21234,19 @@ class Composer extends owl.Component {
|
|
|
21125
21234
|
if (this.compositionActive) {
|
|
21126
21235
|
return;
|
|
21127
21236
|
}
|
|
21128
|
-
const oldScroll = getElementScrollTop(this.composerRef.el);
|
|
21129
|
-
this.contentHelper.removeAll(); // removes the content of the composer, to be added just after
|
|
21130
21237
|
this.shouldProcessInputEvents = false;
|
|
21131
21238
|
if (this.props.focus !== "inactive") {
|
|
21132
21239
|
this.contentHelper.el.focus();
|
|
21133
|
-
this.contentHelper.selectRange(0, 0); // move the cursor inside the composer at 0 0.
|
|
21134
21240
|
}
|
|
21135
21241
|
const content = this.getContentLines();
|
|
21242
|
+
this.contentHelper.setText(content);
|
|
21136
21243
|
if (content.length !== 0 && content.length[0] !== 0) {
|
|
21137
|
-
this.contentHelper.setText(content);
|
|
21138
|
-
const { start, end } = this.env.model.getters.getComposerSelection();
|
|
21139
21244
|
if (this.props.focus !== "inactive") {
|
|
21140
21245
|
// Put the cursor back where it was before the rendering
|
|
21246
|
+
const { start, end } = this.env.model.getters.getComposerSelection();
|
|
21141
21247
|
this.contentHelper.selectRange(start, end);
|
|
21142
21248
|
}
|
|
21143
|
-
|
|
21249
|
+
this.contentHelper.scrollSelectionIntoView();
|
|
21144
21250
|
}
|
|
21145
21251
|
this.shouldProcessInputEvents = true;
|
|
21146
21252
|
}
|
|
@@ -21395,8 +21501,8 @@ class GridComposer extends owl.Component {
|
|
|
21395
21501
|
height: el.clientHeight,
|
|
21396
21502
|
};
|
|
21397
21503
|
this.composerState.delimitation = {
|
|
21398
|
-
width:
|
|
21399
|
-
height:
|
|
21504
|
+
width: this.props.gridDims.width,
|
|
21505
|
+
height: this.props.gridDims.height,
|
|
21400
21506
|
};
|
|
21401
21507
|
});
|
|
21402
21508
|
owl.onWillUpdateProps(() => {
|
|
@@ -23114,7 +23220,7 @@ class Highlight extends owl.Component {
|
|
|
23114
23220
|
shiftingMode: "none",
|
|
23115
23221
|
});
|
|
23116
23222
|
onResizeHighlight(isLeft, isTop) {
|
|
23117
|
-
const
|
|
23223
|
+
const activeSheetId = this.env.model.getters.getActiveSheetId();
|
|
23118
23224
|
this.highlightState.shiftingMode = "isResizing";
|
|
23119
23225
|
const z = this.props.zone;
|
|
23120
23226
|
const pivotCol = isLeft ? z.right : z.left;
|
|
@@ -23123,11 +23229,10 @@ class Highlight extends owl.Component {
|
|
|
23123
23229
|
let lastRow = isTop ? z.top : z.bottom;
|
|
23124
23230
|
let currentZone = z;
|
|
23125
23231
|
this.env.model.dispatch("START_CHANGE_HIGHLIGHT", {
|
|
23126
|
-
range: this.env.model.getters.getRangeDataFromZone(
|
|
23232
|
+
range: this.env.model.getters.getRangeDataFromZone(activeSheetId, currentZone),
|
|
23127
23233
|
});
|
|
23128
23234
|
const mouseMove = (col, row) => {
|
|
23129
23235
|
if (lastCol !== col || lastRow !== row) {
|
|
23130
|
-
const activeSheetId = this.env.model.getters.getActiveSheetId();
|
|
23131
23236
|
lastCol = clip(col === -1 ? lastCol : col, 0, this.env.model.getters.getNumberCols(activeSheetId) - 1);
|
|
23132
23237
|
lastRow = clip(row === -1 ? lastRow : row, 0, this.env.model.getters.getNumberRows(activeSheetId) - 1);
|
|
23133
23238
|
let newZone = {
|
|
@@ -23139,7 +23244,7 @@ class Highlight extends owl.Component {
|
|
|
23139
23244
|
newZone = this.env.model.getters.expandZone(activeSheetId, newZone);
|
|
23140
23245
|
if (!isEqual(newZone, currentZone)) {
|
|
23141
23246
|
this.env.model.dispatch("CHANGE_HIGHLIGHT", {
|
|
23142
|
-
range: this.env.model.getters.
|
|
23247
|
+
range: this.env.model.getters.getRangeFromZone(activeSheetId, this.env.model.getters.getUnboundedZone(activeSheetId, newZone)).rangeData,
|
|
23143
23248
|
});
|
|
23144
23249
|
currentZone = newZone;
|
|
23145
23250
|
}
|
|
@@ -23186,7 +23291,7 @@ class Highlight extends owl.Component {
|
|
|
23186
23291
|
newZone = this.env.model.getters.expandZone(activeSheetId, newZone);
|
|
23187
23292
|
if (!isEqual(newZone, currentZone)) {
|
|
23188
23293
|
this.env.model.dispatch("CHANGE_HIGHLIGHT", {
|
|
23189
|
-
range: this.env.model.getters.
|
|
23294
|
+
range: this.env.model.getters.getRangeFromZone(activeSheetId, this.env.model.getters.getUnboundedZone(activeSheetId, newZone)).rangeData,
|
|
23190
23295
|
});
|
|
23191
23296
|
currentZone = newZone;
|
|
23192
23297
|
}
|
|
@@ -24508,6 +24613,16 @@ const XLSX_INDEXED_COLORS = {
|
|
|
24508
24613
|
63: "333333",
|
|
24509
24614
|
64: "000000",
|
|
24510
24615
|
65: "FFFFFF", // system background
|
|
24616
|
+
};
|
|
24617
|
+
const IMAGE_MIMETYPE_EXTENSION_MAPPING = {
|
|
24618
|
+
"image/avif": "avif",
|
|
24619
|
+
"image/bmp": "bmp",
|
|
24620
|
+
"image/gif": "gif",
|
|
24621
|
+
"image/vnd.microsoft.icon": "ico",
|
|
24622
|
+
"image/jpeg": "jpeg",
|
|
24623
|
+
"image/png": "png",
|
|
24624
|
+
"image/tiff": "tiff",
|
|
24625
|
+
"image/webp": "webp",
|
|
24511
24626
|
};
|
|
24512
24627
|
|
|
24513
24628
|
/**
|
|
@@ -26990,6 +27105,11 @@ function createOverride(partName, contentType) {
|
|
|
26990
27105
|
<Override ContentType="${contentType}" PartName="${partName}" />
|
|
26991
27106
|
`;
|
|
26992
27107
|
}
|
|
27108
|
+
function createDefaultXMLElement(extension, contentType) {
|
|
27109
|
+
return escapeXml /*xml*/ `
|
|
27110
|
+
<Default Extension="${extension}" ContentType="${contentType}" />
|
|
27111
|
+
`;
|
|
27112
|
+
}
|
|
26993
27113
|
function joinXmlNodes(xmlNodes) {
|
|
26994
27114
|
return new XMLString(xmlNodes.join("\n"));
|
|
26995
27115
|
}
|
|
@@ -28855,11 +28975,9 @@ class BasePlugin {
|
|
|
28855
28975
|
*/
|
|
28856
28976
|
class CorePlugin extends BasePlugin {
|
|
28857
28977
|
getters;
|
|
28858
|
-
range;
|
|
28859
28978
|
uuidGenerator;
|
|
28860
28979
|
constructor({ getters, stateObserver, range, dispatch, uuidGenerator }) {
|
|
28861
28980
|
super(stateObserver, dispatch);
|
|
28862
|
-
this.range = range;
|
|
28863
28981
|
range.addRangeProvider(this.adaptRanges.bind(this));
|
|
28864
28982
|
this.getters = getters;
|
|
28865
28983
|
this.uuidGenerator = uuidGenerator;
|
|
@@ -31433,6 +31551,7 @@ class MergePlugin extends CorePlugin {
|
|
|
31433
31551
|
"getMerge",
|
|
31434
31552
|
"getMergesInZone",
|
|
31435
31553
|
"isSingleCellOrMerge",
|
|
31554
|
+
"getSelectionRangeString",
|
|
31436
31555
|
];
|
|
31437
31556
|
nextId = 1;
|
|
31438
31557
|
merges = {};
|
|
@@ -31520,6 +31639,26 @@ class MergePlugin extends CorePlugin {
|
|
|
31520
31639
|
.map((mergeId) => this.getMergeById(sheetId, mergeId))
|
|
31521
31640
|
.filter(isDefined$1);
|
|
31522
31641
|
}
|
|
31642
|
+
/**
|
|
31643
|
+
* Same as `getRangeString` but add all necessary merge to the range to make it a valid selection
|
|
31644
|
+
*/
|
|
31645
|
+
getSelectionRangeString(range, forSheetId) {
|
|
31646
|
+
const rangeImpl = RangeImpl.fromRange(range, this.getters);
|
|
31647
|
+
const expandedZone = this.getters.expandZone(rangeImpl.sheetId, rangeImpl.zone);
|
|
31648
|
+
const expandedRange = rangeImpl.clone({
|
|
31649
|
+
zone: {
|
|
31650
|
+
...expandedZone,
|
|
31651
|
+
bottom: rangeImpl.isFullCol ? undefined : expandedZone.bottom,
|
|
31652
|
+
right: rangeImpl.isFullRow ? undefined : expandedZone.right,
|
|
31653
|
+
},
|
|
31654
|
+
});
|
|
31655
|
+
const rangeString = this.getters.getRangeString(expandedRange, forSheetId);
|
|
31656
|
+
if (this.isSingleCellOrMerge(rangeImpl.sheetId, rangeImpl.zone)) {
|
|
31657
|
+
const { sheetName, xc } = splitReference(rangeString);
|
|
31658
|
+
return `${sheetName !== undefined ? getCanonicalSheetName(sheetName) + "!" : ""}${xc.split(":")[0]}`;
|
|
31659
|
+
}
|
|
31660
|
+
return rangeString;
|
|
31661
|
+
}
|
|
31523
31662
|
/**
|
|
31524
31663
|
* Return true if the zone intersects an existing merge:
|
|
31525
31664
|
* if they have at least a common cell
|
|
@@ -31852,12 +31991,12 @@ class RangeAdapter {
|
|
|
31852
31991
|
}
|
|
31853
31992
|
static getters = [
|
|
31854
31993
|
"getRangeString",
|
|
31855
|
-
"getSelectionRangeString",
|
|
31856
31994
|
"getRangeFromSheetXC",
|
|
31857
31995
|
"createAdaptedRanges",
|
|
31858
31996
|
"getRangeDataFromXc",
|
|
31859
31997
|
"getRangeDataFromZone",
|
|
31860
31998
|
"getRangeFromRangeData",
|
|
31999
|
+
"getRangeFromZone",
|
|
31861
32000
|
];
|
|
31862
32001
|
// ---------------------------------------------------------------------------
|
|
31863
32002
|
// Command Handling
|
|
@@ -32106,21 +32245,6 @@ class RangeAdapter {
|
|
|
32106
32245
|
const rangeInterface = { prefixSheet, zone, sheetId, invalidSheetName, parts };
|
|
32107
32246
|
return new RangeImpl(rangeInterface, this.getters.getSheetSize).orderZone();
|
|
32108
32247
|
}
|
|
32109
|
-
/**
|
|
32110
|
-
* Same as `getRangeString` but add all necessary merge to the range to make it a valid selection
|
|
32111
|
-
*/
|
|
32112
|
-
getSelectionRangeString(range, forSheetId) {
|
|
32113
|
-
const rangeImpl = RangeImpl.fromRange(range, this.getters);
|
|
32114
|
-
const expandedZone = this.getters.expandZone(rangeImpl.sheetId, rangeImpl.zone);
|
|
32115
|
-
const expandedRange = rangeImpl.clone({
|
|
32116
|
-
zone: {
|
|
32117
|
-
...expandedZone,
|
|
32118
|
-
bottom: rangeImpl.isFullCol ? undefined : expandedZone.bottom,
|
|
32119
|
-
right: rangeImpl.isFullRow ? undefined : expandedZone.right,
|
|
32120
|
-
},
|
|
32121
|
-
});
|
|
32122
|
-
return this.getRangeString(expandedRange, forSheetId);
|
|
32123
|
-
}
|
|
32124
32248
|
/**
|
|
32125
32249
|
* Gets the string that represents the range as it is at the moment of the call.
|
|
32126
32250
|
* The string will be prefixed with the sheet name if the call specified a sheet id in `forSheetId`
|
|
@@ -32177,6 +32301,17 @@ class RangeAdapter {
|
|
|
32177
32301
|
getRangeDataFromZone(sheetId, zone) {
|
|
32178
32302
|
return { _sheetId: sheetId, _zone: zone };
|
|
32179
32303
|
}
|
|
32304
|
+
getRangeFromZone(sheetId, zone) {
|
|
32305
|
+
return new RangeImpl({
|
|
32306
|
+
sheetId,
|
|
32307
|
+
zone,
|
|
32308
|
+
parts: [
|
|
32309
|
+
{ colFixed: false, rowFixed: false },
|
|
32310
|
+
{ colFixed: false, rowFixed: false },
|
|
32311
|
+
],
|
|
32312
|
+
prefixSheet: false,
|
|
32313
|
+
}, this.getters.getSheetSize);
|
|
32314
|
+
}
|
|
32180
32315
|
getRangeFromRangeData(data) {
|
|
32181
32316
|
const rangeInterface = {
|
|
32182
32317
|
prefixSheet: false,
|
|
@@ -32262,6 +32397,7 @@ class SheetPlugin extends CorePlugin {
|
|
|
32262
32397
|
"getPaneDivisions",
|
|
32263
32398
|
"checkZonesExistInSheet",
|
|
32264
32399
|
"getCommandZones",
|
|
32400
|
+
"getUnboundedZone",
|
|
32265
32401
|
];
|
|
32266
32402
|
sheetIdsMapName = {};
|
|
32267
32403
|
orderedSheetIds = [];
|
|
@@ -32587,6 +32723,16 @@ class SheetPlugin extends CorePlugin {
|
|
|
32587
32723
|
right: this.getNumberCols(sheetId) - 1,
|
|
32588
32724
|
};
|
|
32589
32725
|
}
|
|
32726
|
+
getUnboundedZone(sheetId, zone) {
|
|
32727
|
+
const isFullRow = zone.left === 0 && zone.right === this.getNumberCols(sheetId) - 1;
|
|
32728
|
+
const isFullCol = zone.top === 0 && zone.bottom === this.getNumberRows(sheetId) - 1;
|
|
32729
|
+
return {
|
|
32730
|
+
...zone,
|
|
32731
|
+
bottom: isFullCol ? undefined : zone.bottom,
|
|
32732
|
+
// cannot be unbounded in the 2 dimensions at once
|
|
32733
|
+
right: isFullRow && !isFullCol ? undefined : zone.right,
|
|
32734
|
+
};
|
|
32735
|
+
}
|
|
32590
32736
|
getPaneDivisions(sheetId) {
|
|
32591
32737
|
return this.getSheet(sheetId).panes;
|
|
32592
32738
|
}
|
|
@@ -38622,6 +38768,7 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
38622
38768
|
// ---------------------------------------------------------------------------
|
|
38623
38769
|
allowDispatch(cmd) {
|
|
38624
38770
|
switch (cmd.type) {
|
|
38771
|
+
case "ADD_RANGE":
|
|
38625
38772
|
case "ADD_EMPTY_RANGE":
|
|
38626
38773
|
if (this.inputHasSingleRange && this.ranges.length === 1) {
|
|
38627
38774
|
return 30 /* CommandResult.MaximumRangesReached */;
|
|
@@ -38636,11 +38783,11 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
38636
38783
|
return 0 /* CommandResult.Success */;
|
|
38637
38784
|
}
|
|
38638
38785
|
handleEvent(event) {
|
|
38639
|
-
const xc = zoneToXc(event.anchor.zone);
|
|
38640
38786
|
const inputSheetId = this.activeSheet;
|
|
38641
38787
|
const sheetId = this.getters.getActiveSheetId();
|
|
38642
|
-
const
|
|
38643
|
-
this.
|
|
38788
|
+
const zone = event.anchor.zone;
|
|
38789
|
+
const range = this.getters.getRangeFromZone(sheetId, event.type === "HeadersSelected" ? this.getters.getUnboundedZone(sheetId, zone) : zone);
|
|
38790
|
+
this.add([this.getters.getSelectionRangeString(range, inputSheetId)]);
|
|
38644
38791
|
}
|
|
38645
38792
|
handle(cmd) {
|
|
38646
38793
|
switch (cmd.type) {
|
|
@@ -38666,6 +38813,10 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
38666
38813
|
this.insertNewRange(this.ranges.length, [""]);
|
|
38667
38814
|
this.focusLast();
|
|
38668
38815
|
break;
|
|
38816
|
+
case "ADD_RANGE":
|
|
38817
|
+
this.insertNewRange(this.ranges.length, [cmd.value]);
|
|
38818
|
+
this.focusLast();
|
|
38819
|
+
break;
|
|
38669
38820
|
case "REMOVE_RANGE":
|
|
38670
38821
|
const index = this.getIndex(cmd.rangeId);
|
|
38671
38822
|
if (index !== null) {
|
|
@@ -38877,6 +39028,7 @@ class SelectionInputsManagerPlugin extends UIPlugin {
|
|
|
38877
39028
|
case "UNFOCUS_SELECTION_INPUT":
|
|
38878
39029
|
this.unfocus();
|
|
38879
39030
|
break;
|
|
39031
|
+
case "ADD_RANGE":
|
|
38880
39032
|
case "ADD_EMPTY_RANGE":
|
|
38881
39033
|
case "REMOVE_RANGE":
|
|
38882
39034
|
if (cmd.id !== this.focusedInputId) {
|
|
@@ -38890,9 +39042,11 @@ class SelectionInputsManagerPlugin extends UIPlugin {
|
|
|
38890
39042
|
if (cmd.id !== this.focusedInputId) {
|
|
38891
39043
|
const input = this.inputs[cmd.id];
|
|
38892
39044
|
const range = input.ranges.find((range) => range.id === cmd.rangeId);
|
|
38893
|
-
|
|
38894
|
-
|
|
38895
|
-
|
|
39045
|
+
if (this.isRangeValid(range?.xc || "A1")) {
|
|
39046
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
39047
|
+
const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
|
|
39048
|
+
this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, { handleEvent: input.handleEvent.bind(input) });
|
|
39049
|
+
}
|
|
38896
39050
|
this.focusedInputId = cmd.id;
|
|
38897
39051
|
}
|
|
38898
39052
|
break;
|
|
@@ -41091,12 +41245,20 @@ class EditionPlugin extends UIPlugin {
|
|
|
41091
41245
|
if (this.mode !== "selecting") {
|
|
41092
41246
|
return;
|
|
41093
41247
|
}
|
|
41248
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
41249
|
+
let unboundedZone;
|
|
41250
|
+
if (event.type === "HeadersSelected") {
|
|
41251
|
+
unboundedZone = this.getters.getUnboundedZone(sheetId, event.anchor.zone);
|
|
41252
|
+
}
|
|
41253
|
+
else {
|
|
41254
|
+
unboundedZone = event.anchor.zone;
|
|
41255
|
+
}
|
|
41094
41256
|
switch (event.mode) {
|
|
41095
41257
|
case "newAnchor":
|
|
41096
|
-
this.insertSelectedRange(
|
|
41258
|
+
this.insertSelectedRange(unboundedZone);
|
|
41097
41259
|
break;
|
|
41098
41260
|
default:
|
|
41099
|
-
this.replaceSelectedRanges(
|
|
41261
|
+
this.replaceSelectedRanges(unboundedZone);
|
|
41100
41262
|
break;
|
|
41101
41263
|
}
|
|
41102
41264
|
}
|
|
@@ -41153,7 +41315,9 @@ class EditionPlugin extends UIPlugin {
|
|
|
41153
41315
|
}
|
|
41154
41316
|
break;
|
|
41155
41317
|
case "START_CHANGE_HIGHLIGHT":
|
|
41318
|
+
// FIXME: thiws whole ordeal could be handled with the Selection Processor which would extend the feature to selection inputs
|
|
41156
41319
|
this.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
41320
|
+
// FIXME: we should check range SheetId compared to this.activeSheetId r maybe not have a sheetId in the payload ??
|
|
41157
41321
|
const range = this.getters.getRangeFromRangeData(cmd.range);
|
|
41158
41322
|
const previousRefToken = this.currentTokens
|
|
41159
41323
|
.filter((token) => token.type === "REFERENCE")
|
|
@@ -41507,14 +41671,11 @@ class EditionPlugin extends UIPlugin {
|
|
|
41507
41671
|
const ref = this.getZoneReference(zone);
|
|
41508
41672
|
this.replaceText(ref, this.selectionInitialStart, this.selectionEnd);
|
|
41509
41673
|
}
|
|
41510
|
-
getZoneReference(zone
|
|
41674
|
+
getZoneReference(zone) {
|
|
41675
|
+
const inputSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
41511
41676
|
const sheetId = this.getters.getActiveSheetId();
|
|
41512
|
-
|
|
41513
|
-
|
|
41514
|
-
const sheetName = getCanonicalSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
|
|
41515
|
-
selectedXc = `${sheetName}!${selectedXc}`;
|
|
41516
|
-
}
|
|
41517
|
-
return selectedXc;
|
|
41677
|
+
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
41678
|
+
return this.getters.getSelectionRangeString(range, inputSheetId);
|
|
41518
41679
|
}
|
|
41519
41680
|
getRangeReference(range, fixedParts = [{ colFixed: false, rowFixed: false }]) {
|
|
41520
41681
|
let _fixedParts = [...fixedParts];
|
|
@@ -42368,7 +42529,7 @@ class ImageProvider {
|
|
|
42368
42529
|
const file = await this.getImageFromUser();
|
|
42369
42530
|
const path = await this.fileStore.upload(file);
|
|
42370
42531
|
const size = await this.getImageSize(path);
|
|
42371
|
-
return { path, size };
|
|
42532
|
+
return { path, size, mimetype: file.type };
|
|
42372
42533
|
}
|
|
42373
42534
|
getImageFromUser() {
|
|
42374
42535
|
return new Promise((resolve, reject) => {
|
|
@@ -47435,8 +47596,7 @@ function createWorksheets(data, construct) {
|
|
|
47435
47596
|
// Figures and Charts
|
|
47436
47597
|
let drawingNode = escapeXml ``;
|
|
47437
47598
|
const drawingRelIds = [];
|
|
47438
|
-
const
|
|
47439
|
-
for (const chart of charts) {
|
|
47599
|
+
for (const chart of sheet.charts) {
|
|
47440
47600
|
const xlsxChartId = convertChartId(chart.id);
|
|
47441
47601
|
const chartRelId = addRelsToFile(construct.relsFiles, `xl/drawings/_rels/drawing${sheetIndex}.xml.rels`, {
|
|
47442
47602
|
target: `../charts/chart${xlsxChartId}.xml`,
|
|
@@ -47445,20 +47605,27 @@ function createWorksheets(data, construct) {
|
|
|
47445
47605
|
drawingRelIds.push(chartRelId);
|
|
47446
47606
|
files.push(createXMLFile(createChart(chart, sheetIndex, data), `xl/charts/chart${xlsxChartId}.xml`, "chart"));
|
|
47447
47607
|
}
|
|
47448
|
-
const
|
|
47449
|
-
|
|
47608
|
+
for (const image of sheet.images) {
|
|
47609
|
+
const mimeType = image.data.mimetype;
|
|
47610
|
+
if (mimeType === undefined)
|
|
47611
|
+
continue;
|
|
47612
|
+
const extension = IMAGE_MIMETYPE_EXTENSION_MAPPING[mimeType];
|
|
47613
|
+
// only support exporting images with mimetypes specified in the mapping
|
|
47614
|
+
if (extension === undefined)
|
|
47615
|
+
continue;
|
|
47450
47616
|
const xlsxImageId = convertImageId(image.id);
|
|
47617
|
+
let imageFileName = `image${xlsxImageId}.${extension}`;
|
|
47451
47618
|
const imageRelId = addRelsToFile(construct.relsFiles, `xl/drawings/_rels/drawing${sheetIndex}.xml.rels`, {
|
|
47452
|
-
target: `../media
|
|
47619
|
+
target: `../media/${imageFileName}`,
|
|
47453
47620
|
type: XLSX_RELATION_TYPE.image,
|
|
47454
47621
|
});
|
|
47455
47622
|
drawingRelIds.push(imageRelId);
|
|
47456
47623
|
files.push({
|
|
47457
|
-
path: `xl/media
|
|
47458
|
-
|
|
47624
|
+
path: `xl/media/${imageFileName}`,
|
|
47625
|
+
imageSrc: image.data.path,
|
|
47459
47626
|
});
|
|
47460
47627
|
}
|
|
47461
|
-
const drawings = [...charts, ...images];
|
|
47628
|
+
const drawings = [...sheet.charts, ...sheet.images];
|
|
47462
47629
|
if (drawings.length) {
|
|
47463
47630
|
const drawingRelId = addRelsToFile(construct.relsFiles, `xl/worksheets/_rels/sheet${sheetIndex}.xml.rels`, {
|
|
47464
47631
|
target: `../drawings/drawing${sheetIndex}.xml`,
|
|
@@ -47577,6 +47744,8 @@ function createRelsFiles(relsFiles) {
|
|
|
47577
47744
|
}
|
|
47578
47745
|
function createContentTypes(files) {
|
|
47579
47746
|
const overrideNodes = [];
|
|
47747
|
+
// hard-code supported image mimetypes
|
|
47748
|
+
const imageDefaultNodes = Object.entries(IMAGE_MIMETYPE_EXTENSION_MAPPING).map(([mimetype, extension]) => createDefaultXMLElement(extension, mimetype));
|
|
47580
47749
|
for (const file of files) {
|
|
47581
47750
|
if ("contentType" in file && file.contentType) {
|
|
47582
47751
|
overrideNodes.push(createOverride("/" + file.path, CONTENT_TYPES[file.contentType]));
|
|
@@ -47592,6 +47761,7 @@ function createContentTypes(files) {
|
|
|
47592
47761
|
];
|
|
47593
47762
|
const xml = escapeXml /*xml*/ `
|
|
47594
47763
|
<Types xmlns="${NAMESPACE["Types"]}">
|
|
47764
|
+
${joinXmlNodes(Object.values(imageDefaultNodes))}
|
|
47595
47765
|
<Default ${formatAttributes(relsAttributes)} />
|
|
47596
47766
|
<Default ${formatAttributes(xmlAttributes)} />
|
|
47597
47767
|
${joinXmlNodes(overrideNodes)}
|
|
@@ -47683,7 +47853,7 @@ class Model extends EventBus {
|
|
|
47683
47853
|
this.coreGetters.getRangeDataFromXc = this.range.getRangeDataFromXc.bind(this.range);
|
|
47684
47854
|
this.coreGetters.getRangeDataFromZone = this.range.getRangeDataFromZone.bind(this.range);
|
|
47685
47855
|
this.coreGetters.getRangeFromRangeData = this.range.getRangeFromRangeData.bind(this.range);
|
|
47686
|
-
this.coreGetters.
|
|
47856
|
+
this.coreGetters.getRangeFromZone = this.range.getRangeFromZone.bind(this.range);
|
|
47687
47857
|
this.getters = {
|
|
47688
47858
|
isReadonly: () => this.config.mode === "readonly" || this.config.mode === "dashboard",
|
|
47689
47859
|
isDashboard: () => this.config.mode === "dashboard",
|
|
@@ -48191,6 +48361,8 @@ exports.coreTypes = coreTypes;
|
|
|
48191
48361
|
exports.findCellInNewZone = findCellInNewZone;
|
|
48192
48362
|
exports.functionCache = functionCache;
|
|
48193
48363
|
exports.helpers = helpers;
|
|
48364
|
+
exports.invalidateCFEvaluationCommands = invalidateCFEvaluationCommands;
|
|
48365
|
+
exports.invalidateDependenciesCommands = invalidateDependenciesCommands;
|
|
48194
48366
|
exports.invalidateEvaluationCommands = invalidateEvaluationCommands;
|
|
48195
48367
|
exports.links = links;
|
|
48196
48368
|
exports.load = load;
|
|
@@ -48202,6 +48374,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
48202
48374
|
exports.tokenize = tokenize;
|
|
48203
48375
|
|
|
48204
48376
|
|
|
48205
|
-
__info__.version = '16.4.0-alpha.
|
|
48206
|
-
__info__.date = '2023-
|
|
48207
|
-
__info__.hash = '
|
|
48377
|
+
__info__.version = '16.4.0-alpha.3';
|
|
48378
|
+
__info__.date = '2023-06-02T10:13:30.127Z';
|
|
48379
|
+
__info__.hash = '059d66a';
|