@odoo/o-spreadsheet 18.4.0-alpha.9 → 18.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/o-spreadsheet.cjs.js +1117 -229
- package/dist/o-spreadsheet.d.ts +153 -51
- package/dist/o-spreadsheet.esm.js +1117 -229
- package/dist/o-spreadsheet.iife.js +1117 -229
- package/dist/o-spreadsheet.iife.min.js +412 -400
- package/dist/o_spreadsheet.xml +76 -22
- package/package.json +2 -2
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 18.4.
|
|
6
|
-
* @date 2025-06-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.4.1
|
|
6
|
+
* @date 2025-06-27T09:13:01.303Z
|
|
7
|
+
* @hash 5cecc0e
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -163,6 +163,7 @@
|
|
|
163
163
|
const FROZEN_PANE_BORDER_COLOR = "#DADFE8";
|
|
164
164
|
const COMPOSER_ASSISTANT_COLOR = "#9B359B";
|
|
165
165
|
const COLOR_TRANSPARENT = "#00000000";
|
|
166
|
+
const TABLE_HOVER_BACKGROUND_COLOR = "#017E8414";
|
|
166
167
|
const CHART_WATERFALL_POSITIVE_COLOR = "#4EA7F2";
|
|
167
168
|
const CHART_WATERFALL_NEGATIVE_COLOR = "#EA6175";
|
|
168
169
|
const CHART_WATERFALL_SUBTOTAL_COLOR = "#AAAAAA";
|
|
@@ -6848,19 +6849,17 @@
|
|
|
6848
6849
|
const textWidthCache = {};
|
|
6849
6850
|
function computeTextWidth(context, text, style, fontUnit = "pt") {
|
|
6850
6851
|
const font = computeTextFont(style, fontUnit);
|
|
6851
|
-
context
|
|
6852
|
-
context.font = font;
|
|
6853
|
-
const width = computeCachedTextWidth(context, text);
|
|
6854
|
-
context.restore();
|
|
6855
|
-
return width;
|
|
6852
|
+
return computeCachedTextWidth(context, text, font);
|
|
6856
6853
|
}
|
|
6857
|
-
function computeCachedTextWidth(context, text) {
|
|
6858
|
-
const font = context.font;
|
|
6854
|
+
function computeCachedTextWidth(context, text, font) {
|
|
6859
6855
|
if (!textWidthCache[font]) {
|
|
6860
6856
|
textWidthCache[font] = {};
|
|
6861
6857
|
}
|
|
6862
6858
|
if (textWidthCache[font][text] === undefined) {
|
|
6859
|
+
const oldFont = context.font;
|
|
6860
|
+
context.font = font;
|
|
6863
6861
|
textWidthCache[font][text] = context.measureText(text).width;
|
|
6862
|
+
context.font = oldFont;
|
|
6864
6863
|
}
|
|
6865
6864
|
return textWidthCache[font][text];
|
|
6866
6865
|
}
|
|
@@ -7025,19 +7024,19 @@
|
|
|
7025
7024
|
}
|
|
7026
7025
|
// Inspired from https://stackoverflow.com/a/10511598
|
|
7027
7026
|
function clipTextWithEllipsis(ctx, text, maxWidth) {
|
|
7028
|
-
let width = computeCachedTextWidth(ctx, text);
|
|
7027
|
+
let width = computeCachedTextWidth(ctx, text, ctx.font);
|
|
7029
7028
|
if (width <= maxWidth) {
|
|
7030
7029
|
return text;
|
|
7031
7030
|
}
|
|
7032
7031
|
const ellipsis = "…";
|
|
7033
|
-
const ellipsisWidth = computeCachedTextWidth(ctx, ellipsis);
|
|
7032
|
+
const ellipsisWidth = computeCachedTextWidth(ctx, ellipsis, ctx.font);
|
|
7034
7033
|
if (width <= ellipsisWidth) {
|
|
7035
7034
|
return text;
|
|
7036
7035
|
}
|
|
7037
7036
|
let len = text.length;
|
|
7038
7037
|
while (width >= maxWidth - ellipsisWidth && len-- > 0) {
|
|
7039
7038
|
text = text.substring(0, len);
|
|
7040
|
-
width = computeCachedTextWidth(ctx, text);
|
|
7039
|
+
width = computeCachedTextWidth(ctx, text, ctx.font);
|
|
7041
7040
|
}
|
|
7042
7041
|
return text + ellipsis;
|
|
7043
7042
|
}
|
|
@@ -7251,6 +7250,63 @@
|
|
|
7251
7250
|
};
|
|
7252
7251
|
return osClipboardContent;
|
|
7253
7252
|
}
|
|
7253
|
+
/**
|
|
7254
|
+
* Applies each clipboard handler to paste its corresponding data into the target.
|
|
7255
|
+
*/
|
|
7256
|
+
const applyClipboardHandlersPaste = (handlers, copiedData, target, options) => {
|
|
7257
|
+
handlers.forEach(({ handlerName, handler }) => {
|
|
7258
|
+
const data = copiedData[handlerName];
|
|
7259
|
+
if (data) {
|
|
7260
|
+
handler.paste(target, data, options);
|
|
7261
|
+
}
|
|
7262
|
+
});
|
|
7263
|
+
};
|
|
7264
|
+
/**
|
|
7265
|
+
* Returns the paste target based on clipboard handlers.
|
|
7266
|
+
* Also includes the full affected zone and the list of pasted zones for selection.
|
|
7267
|
+
*/
|
|
7268
|
+
function getPasteTargetFromHandlers(sheetId, zones, copiedData, handlers, options) {
|
|
7269
|
+
let zone = undefined;
|
|
7270
|
+
const selectedZones = [];
|
|
7271
|
+
const target = {
|
|
7272
|
+
sheetId,
|
|
7273
|
+
zones,
|
|
7274
|
+
};
|
|
7275
|
+
for (const { handlerName, handler } of handlers) {
|
|
7276
|
+
const handlerData = copiedData[handlerName];
|
|
7277
|
+
if (!handlerData) {
|
|
7278
|
+
continue;
|
|
7279
|
+
}
|
|
7280
|
+
const currentTarget = handler.getPasteTarget(sheetId, zones, handlerData, options);
|
|
7281
|
+
if (currentTarget.figureId) {
|
|
7282
|
+
target.figureId = currentTarget.figureId;
|
|
7283
|
+
}
|
|
7284
|
+
for (const targetZone of currentTarget.zones) {
|
|
7285
|
+
selectedZones.push(targetZone);
|
|
7286
|
+
if (zone === undefined) {
|
|
7287
|
+
zone = targetZone;
|
|
7288
|
+
continue;
|
|
7289
|
+
}
|
|
7290
|
+
zone = union(zone, targetZone);
|
|
7291
|
+
}
|
|
7292
|
+
}
|
|
7293
|
+
return {
|
|
7294
|
+
target,
|
|
7295
|
+
zone,
|
|
7296
|
+
selectedZones,
|
|
7297
|
+
};
|
|
7298
|
+
}
|
|
7299
|
+
/**
|
|
7300
|
+
* Updates the selection after a paste operation.
|
|
7301
|
+
*/
|
|
7302
|
+
const selectPastedZone = (selection, sourceZones, pastedZones) => {
|
|
7303
|
+
const anchorCell = {
|
|
7304
|
+
col: sourceZones[0].left,
|
|
7305
|
+
row: sourceZones[0].top,
|
|
7306
|
+
};
|
|
7307
|
+
selection.getBackToDefault();
|
|
7308
|
+
selection.selectZone({ cell: anchorCell, zone: union(...pastedZones) }, { scrollIntoView: false });
|
|
7309
|
+
};
|
|
7254
7310
|
|
|
7255
7311
|
class ClipboardHandler {
|
|
7256
7312
|
getters;
|
|
@@ -9955,8 +10011,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9955
10011
|
const ModelStore = createAbstractStore("Model");
|
|
9956
10012
|
|
|
9957
10013
|
class RendererStore {
|
|
9958
|
-
mutators = ["register", "unRegister", "
|
|
10014
|
+
mutators = ["register", "unRegister", "draw", "startAnimation", "stopAnimation"];
|
|
9959
10015
|
renderers = {};
|
|
10016
|
+
model;
|
|
10017
|
+
context = undefined;
|
|
10018
|
+
animationFrameId = null;
|
|
10019
|
+
registeredAnimations = new Set();
|
|
10020
|
+
constructor(get) {
|
|
10021
|
+
this.model = get(ModelStore);
|
|
10022
|
+
}
|
|
9960
10023
|
register(renderer) {
|
|
9961
10024
|
if (!renderer.renderingLayers.length) {
|
|
9962
10025
|
return;
|
|
@@ -9973,17 +10036,54 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
9973
10036
|
this.renderers[layer] = this.renderers[layer].filter((r) => r !== renderer);
|
|
9974
10037
|
}
|
|
9975
10038
|
}
|
|
9976
|
-
drawLayer(context, layer) {
|
|
10039
|
+
drawLayer(context, layer, timeStamp) {
|
|
9977
10040
|
const renderers = this.renderers[layer];
|
|
9978
10041
|
if (renderers) {
|
|
9979
10042
|
for (const renderer of renderers) {
|
|
9980
10043
|
context.ctx.save();
|
|
9981
|
-
renderer.drawLayer(context, layer);
|
|
10044
|
+
renderer.drawLayer(context, layer, timeStamp);
|
|
9982
10045
|
context.ctx.restore();
|
|
9983
10046
|
}
|
|
9984
10047
|
}
|
|
9985
10048
|
return "noStateChange";
|
|
9986
10049
|
}
|
|
10050
|
+
draw(context, timestamp) {
|
|
10051
|
+
context = context || this.context;
|
|
10052
|
+
if (!context) {
|
|
10053
|
+
throw new Error("Rendering context is not defined");
|
|
10054
|
+
}
|
|
10055
|
+
this.context = context;
|
|
10056
|
+
for (const layer of OrderedLayers()) {
|
|
10057
|
+
this.model.drawLayer(context, layer);
|
|
10058
|
+
this.drawLayer(context, layer, timestamp);
|
|
10059
|
+
}
|
|
10060
|
+
return "noStateChange";
|
|
10061
|
+
}
|
|
10062
|
+
startAnimation(animationId) {
|
|
10063
|
+
this.registeredAnimations.add(animationId);
|
|
10064
|
+
if (!this.animationFrameId) {
|
|
10065
|
+
const animationCallback = (timestamp) => {
|
|
10066
|
+
this.animationFrameId = requestAnimationFrame(animationCallback);
|
|
10067
|
+
this.draw(undefined, timestamp);
|
|
10068
|
+
};
|
|
10069
|
+
this.animationFrameId = requestAnimationFrame(animationCallback);
|
|
10070
|
+
}
|
|
10071
|
+
return "noStateChange";
|
|
10072
|
+
}
|
|
10073
|
+
stopAnimation(animationId) {
|
|
10074
|
+
this.registeredAnimations.delete(animationId);
|
|
10075
|
+
if (this.registeredAnimations.size === 0 && this.animationFrameId !== null) {
|
|
10076
|
+
cancelAnimationFrame(this.animationFrameId);
|
|
10077
|
+
this.animationFrameId = null;
|
|
10078
|
+
}
|
|
10079
|
+
return "noStateChange";
|
|
10080
|
+
}
|
|
10081
|
+
dispose() {
|
|
10082
|
+
if (this.animationFrameId) {
|
|
10083
|
+
cancelAnimationFrame(this.animationFrameId);
|
|
10084
|
+
this.animationFrameId = null;
|
|
10085
|
+
}
|
|
10086
|
+
}
|
|
9987
10087
|
}
|
|
9988
10088
|
|
|
9989
10089
|
class SpreadsheetStore extends DisposableStore {
|
|
@@ -10007,7 +10107,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
10007
10107
|
}
|
|
10008
10108
|
handle(cmd) { }
|
|
10009
10109
|
finalize() { }
|
|
10010
|
-
drawLayer(ctx, layer) { }
|
|
10110
|
+
drawLayer(ctx, layer, timestamp) { }
|
|
10011
10111
|
}
|
|
10012
10112
|
|
|
10013
10113
|
const VOID_COMPOSER = {
|
|
@@ -23729,11 +23829,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23729
23829
|
function getGaugeRenderingConfig(boundingRect, runtime, ctx) {
|
|
23730
23830
|
const maxValue = runtime.maxValue;
|
|
23731
23831
|
const minValue = runtime.minValue;
|
|
23732
|
-
const gaugeValue = runtime
|
|
23832
|
+
const gaugeValue = getGaugeValue(runtime, "animated");
|
|
23733
23833
|
const gaugeRect = getGaugeRect(boundingRect, runtime.title.text);
|
|
23734
23834
|
const gaugeArcWidth = gaugeRect.width / 6;
|
|
23735
23835
|
const gaugePercentage = gaugeValue
|
|
23736
|
-
? (gaugeValue
|
|
23836
|
+
? (gaugeValue - minValue.value) / (maxValue.value - minValue.value)
|
|
23737
23837
|
: 0;
|
|
23738
23838
|
const gaugeValuePosition = {
|
|
23739
23839
|
x: boundingRect.width / 2,
|
|
@@ -23746,7 +23846,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23746
23846
|
}
|
|
23747
23847
|
// Scale down the font size if the text is too long
|
|
23748
23848
|
const maxTextWidth = gaugeRect.width / 2;
|
|
23749
|
-
const gaugeLabel = gaugeValue?.label || "-";
|
|
23849
|
+
const gaugeLabel = runtime.gaugeValue?.label || "-";
|
|
23750
23850
|
if (computeTextWidth(ctx, gaugeLabel, { fontSize: gaugeValueFontSize }, "px") > maxTextWidth) {
|
|
23751
23851
|
gaugeValueFontSize = getFontSizeMatchingWidth(maxTextWidth, gaugeValueFontSize, (fontSize) => computeTextWidth(ctx, gaugeLabel, { fontSize }, "px"));
|
|
23752
23852
|
}
|
|
@@ -23886,7 +23986,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23886
23986
|
return inflectionValues;
|
|
23887
23987
|
}
|
|
23888
23988
|
function getGaugeColor(runtime) {
|
|
23889
|
-
const gaugeValue = runtime
|
|
23989
|
+
const gaugeValue = getGaugeValue(runtime, "final");
|
|
23890
23990
|
if (gaugeValue === undefined) {
|
|
23891
23991
|
return GAUGE_BACKGROUND_COLOR;
|
|
23892
23992
|
}
|
|
@@ -23974,6 +24074,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23974
24074
|
};
|
|
23975
24075
|
return { bottomLeft, bottomRight, topRight, topLeft };
|
|
23976
24076
|
}
|
|
24077
|
+
function getGaugeValue(runtime, mode) {
|
|
24078
|
+
return mode === "animated" && runtime.animationValue !== undefined
|
|
24079
|
+
? runtime.animationValue
|
|
24080
|
+
: runtime.gaugeValue?.value;
|
|
24081
|
+
}
|
|
23977
24082
|
|
|
23978
24083
|
const CHART_COMMON_OPTIONS = {
|
|
23979
24084
|
// https://www.chartjs.org/docs/latest/general/responsive.html
|
|
@@ -26328,6 +26433,365 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
26328
26433
|
return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
|
|
26329
26434
|
}
|
|
26330
26435
|
|
|
26436
|
+
const cellAnimationRegistry = new Registry();
|
|
26437
|
+
cellAnimationRegistry.add("animatedBackgroundColorChange", {
|
|
26438
|
+
id: "animatedBackgroundColorChange",
|
|
26439
|
+
easingFn: "easeOutCubic",
|
|
26440
|
+
hasAnimation: (oldBox, newBox) => {
|
|
26441
|
+
return oldBox?.style?.fillColor !== newBox?.style?.fillColor;
|
|
26442
|
+
},
|
|
26443
|
+
updateAnimation: function (progress, animatedBox, oldBox, newBox) {
|
|
26444
|
+
const colorScale = getColorScale([
|
|
26445
|
+
{ value: 0, color: oldBox.style.fillColor || "#ffffff" },
|
|
26446
|
+
{ value: 1, color: newBox.style.fillColor || "#ffffff" },
|
|
26447
|
+
]);
|
|
26448
|
+
animatedBox.style.fillColor = colorScale(EASING_FN[this.easingFn](progress));
|
|
26449
|
+
},
|
|
26450
|
+
});
|
|
26451
|
+
cellAnimationRegistry.add("animatedTextColorChange", {
|
|
26452
|
+
id: "animatedTextColorChange",
|
|
26453
|
+
easingFn: "easeOutCubic",
|
|
26454
|
+
hasAnimation: (oldBox, newBox) => {
|
|
26455
|
+
return oldBox?.style?.textColor !== newBox?.style?.textColor;
|
|
26456
|
+
},
|
|
26457
|
+
updateAnimation: function (progress, animatedBox, oldBox, newBox) {
|
|
26458
|
+
const colorScale = getColorScale([
|
|
26459
|
+
{ value: 0, color: oldBox.style.textColor || "#000000" },
|
|
26460
|
+
{ value: 1, color: newBox.style.textColor || "#000000" },
|
|
26461
|
+
]);
|
|
26462
|
+
animatedBox.style.textColor = colorScale(EASING_FN[this.easingFn](progress));
|
|
26463
|
+
},
|
|
26464
|
+
});
|
|
26465
|
+
cellAnimationRegistry.add("animatedDataBar", {
|
|
26466
|
+
id: "animatedDataBar",
|
|
26467
|
+
easingFn: "easeOutCubic",
|
|
26468
|
+
hasAnimation: (oldBox, newBox) => {
|
|
26469
|
+
return oldBox?.dataBarFill?.percentage !== newBox?.dataBarFill?.percentage;
|
|
26470
|
+
},
|
|
26471
|
+
updateAnimation: function (progress, animatedBox, oldBox, newBox) {
|
|
26472
|
+
const startingPercentage = oldBox?.dataBarFill?.percentage || 0;
|
|
26473
|
+
const endingPercentage = newBox?.dataBarFill?.percentage || 0;
|
|
26474
|
+
const value = EASING_FN[this.easingFn](progress);
|
|
26475
|
+
const percentage = startingPercentage + (endingPercentage - startingPercentage) * value;
|
|
26476
|
+
animatedBox.dataBarFill = {
|
|
26477
|
+
color: newBox.dataBarFill?.color || oldBox.dataBarFill?.color || "#ffffff",
|
|
26478
|
+
percentage: percentage,
|
|
26479
|
+
};
|
|
26480
|
+
},
|
|
26481
|
+
});
|
|
26482
|
+
cellAnimationRegistry.add("textFadeIn", {
|
|
26483
|
+
id: "textFadeIn",
|
|
26484
|
+
easingFn: "easeInCubic",
|
|
26485
|
+
hasAnimation: (oldBox, newBox) => {
|
|
26486
|
+
const oldText = oldBox?.content?.textLines?.join("\n");
|
|
26487
|
+
const newText = newBox?.content?.textLines?.join("\n");
|
|
26488
|
+
return Boolean(!oldText && newText);
|
|
26489
|
+
},
|
|
26490
|
+
updateAnimation: function (progress, animatedBox, oldBox, newBox) {
|
|
26491
|
+
animatedBox.textOpacity = EASING_FN[this.easingFn](progress);
|
|
26492
|
+
},
|
|
26493
|
+
});
|
|
26494
|
+
cellAnimationRegistry.add("textFadeOut", {
|
|
26495
|
+
id: "textFadeOut",
|
|
26496
|
+
easingFn: "easeOutCubic",
|
|
26497
|
+
hasAnimation: (oldBox, newBox) => {
|
|
26498
|
+
const oldText = oldBox?.content?.textLines?.join("\n");
|
|
26499
|
+
const newText = newBox?.content?.textLines?.join("\n");
|
|
26500
|
+
return Boolean(oldText && !newText);
|
|
26501
|
+
},
|
|
26502
|
+
updateAnimation: function (progress, animatedBox, oldBox, newBox) {
|
|
26503
|
+
const textOpacity = 1 - EASING_FN[this.easingFn](progress);
|
|
26504
|
+
const style = { ...oldBox.style };
|
|
26505
|
+
delete style.fillColor;
|
|
26506
|
+
animatedBox.textOpacity = textOpacity;
|
|
26507
|
+
animatedBox.content = oldBox.content;
|
|
26508
|
+
animatedBox.clipRect = oldBox.clipRect;
|
|
26509
|
+
Object.assign(animatedBox.style, style);
|
|
26510
|
+
},
|
|
26511
|
+
});
|
|
26512
|
+
cellAnimationRegistry.add("iconFadeIn", {
|
|
26513
|
+
id: "iconFadeIn",
|
|
26514
|
+
easingFn: "easeInCubic",
|
|
26515
|
+
hasAnimation: (oldBox, newBox) => {
|
|
26516
|
+
return Boolean((!oldBox?.icons?.left && newBox?.icons?.left) ||
|
|
26517
|
+
(!oldBox?.icons?.right && newBox?.icons?.right) ||
|
|
26518
|
+
(!oldBox?.icons?.center && newBox?.icons?.center));
|
|
26519
|
+
},
|
|
26520
|
+
updateAnimation: function (progress, animatedBox, oldBox, newBox) {
|
|
26521
|
+
const iconOpacity = EASING_FN[this.easingFn](progress);
|
|
26522
|
+
if (animatedBox.icons.left && newBox.icons.left && !oldBox.icons.left) {
|
|
26523
|
+
animatedBox.icons.left.opacity = iconOpacity;
|
|
26524
|
+
}
|
|
26525
|
+
if (animatedBox.icons.right && newBox.icons.right && !oldBox.icons.right) {
|
|
26526
|
+
animatedBox.icons.right.opacity = iconOpacity;
|
|
26527
|
+
}
|
|
26528
|
+
if (animatedBox.icons.center && newBox.icons.center && !oldBox.icons.center) {
|
|
26529
|
+
animatedBox.icons.center.opacity = iconOpacity;
|
|
26530
|
+
}
|
|
26531
|
+
},
|
|
26532
|
+
});
|
|
26533
|
+
cellAnimationRegistry.add("iconFadeOut", {
|
|
26534
|
+
id: "iconFadeOut",
|
|
26535
|
+
easingFn: "easeOutCubic",
|
|
26536
|
+
hasAnimation: (oldBox, newBox) => {
|
|
26537
|
+
return Boolean((oldBox?.icons?.left && !newBox?.icons?.left) ||
|
|
26538
|
+
(oldBox?.icons?.right && !newBox?.icons?.right) ||
|
|
26539
|
+
(oldBox?.icons?.center && !newBox?.icons?.center));
|
|
26540
|
+
},
|
|
26541
|
+
updateAnimation: function (progress, animatedBox, oldBox, newBox) {
|
|
26542
|
+
const iconOpacity = 1 - EASING_FN[this.easingFn](progress);
|
|
26543
|
+
if (!animatedBox.icons) {
|
|
26544
|
+
animatedBox.icons = {};
|
|
26545
|
+
}
|
|
26546
|
+
if (oldBox.icons.left && !newBox.icons.left) {
|
|
26547
|
+
animatedBox.icons.left = { ...oldBox.icons.left, opacity: iconOpacity };
|
|
26548
|
+
}
|
|
26549
|
+
if (oldBox.icons.right && !newBox.icons.right) {
|
|
26550
|
+
animatedBox.icons.right = { ...oldBox.icons.right, opacity: iconOpacity };
|
|
26551
|
+
}
|
|
26552
|
+
if (oldBox.icons.center && !newBox.icons.center) {
|
|
26553
|
+
animatedBox.icons.center = { ...oldBox.icons.center, opacity: iconOpacity };
|
|
26554
|
+
}
|
|
26555
|
+
},
|
|
26556
|
+
});
|
|
26557
|
+
cellAnimationRegistry.add("textChange", {
|
|
26558
|
+
id: "textChange",
|
|
26559
|
+
easingFn: "easeOutCubic",
|
|
26560
|
+
hasAnimation: (oldBox, newBox) => {
|
|
26561
|
+
const oldText = oldBox?.content?.textLines?.join("\n");
|
|
26562
|
+
const newText = newBox?.content?.textLines?.join("\n");
|
|
26563
|
+
// Note: here, we also animate changes to icons layout (margins/size change, or icon appearing/disappearing)
|
|
26564
|
+
// because a change to the icon layout will impact where the text is positioned.
|
|
26565
|
+
return Boolean(oldText && newText && (oldText !== newText || hasIconLayoutChange(newBox, oldBox)));
|
|
26566
|
+
},
|
|
26567
|
+
updateAnimation: function (progress, animatedBox, oldBox, newBox) {
|
|
26568
|
+
const value = EASING_FN[this.easingFn](progress);
|
|
26569
|
+
const slideInY = newBox.y + (value - 1) * newBox.height;
|
|
26570
|
+
const slideOutY = newBox.y + value * newBox.height;
|
|
26571
|
+
const iconLayoutChange = hasIconLayoutChange(newBox, oldBox);
|
|
26572
|
+
const slideInBox = {
|
|
26573
|
+
id: newBox.id + "-text-slide-in",
|
|
26574
|
+
x: newBox.x,
|
|
26575
|
+
y: slideInY,
|
|
26576
|
+
width: newBox.width,
|
|
26577
|
+
height: newBox.height,
|
|
26578
|
+
style: { ...newBox.style },
|
|
26579
|
+
skipCellGridLines: true,
|
|
26580
|
+
content: newBox.content ? { ...newBox.content } : undefined,
|
|
26581
|
+
clipRect: newBox.clipRect || {
|
|
26582
|
+
...newBox,
|
|
26583
|
+
// large width to avoid clipping the text it it didn't have a clipRect before,
|
|
26584
|
+
// we mainly want to clip the Y for the animation
|
|
26585
|
+
x: Math.max(0, newBox.x - (newBox.content?.width || 0)),
|
|
26586
|
+
width: newBox.width + (newBox.content?.width || 0) * 2,
|
|
26587
|
+
},
|
|
26588
|
+
icons: iconLayoutChange
|
|
26589
|
+
? addClipRectToIcons(newBox.icons, newBox)
|
|
26590
|
+
: makeIconsEmpty(newBox.icons),
|
|
26591
|
+
};
|
|
26592
|
+
const slideOutBox = {
|
|
26593
|
+
id: oldBox.id + "-text-slide-out",
|
|
26594
|
+
x: newBox.x,
|
|
26595
|
+
y: slideOutY,
|
|
26596
|
+
width: newBox.width,
|
|
26597
|
+
height: newBox.height,
|
|
26598
|
+
style: { ...oldBox.style },
|
|
26599
|
+
skipCellGridLines: true,
|
|
26600
|
+
content: oldBox.content ? { ...oldBox.content } : undefined,
|
|
26601
|
+
clipRect: oldBox.clipRect || {
|
|
26602
|
+
...newBox,
|
|
26603
|
+
x: Math.max(0, newBox.x - (oldBox.content?.width || 0)),
|
|
26604
|
+
width: newBox.width + (oldBox.content?.width || 0) * 2,
|
|
26605
|
+
},
|
|
26606
|
+
icons: iconLayoutChange
|
|
26607
|
+
? addClipRectToIcons(oldBox.icons, newBox)
|
|
26608
|
+
: makeIconsEmpty(oldBox.icons),
|
|
26609
|
+
};
|
|
26610
|
+
if (newBox.content && oldBox.content && slideInBox.content && slideOutBox.content) {
|
|
26611
|
+
const slideInContentY = newBox.content.y + (value - 1) * newBox.height;
|
|
26612
|
+
const slideOutContentY = newBox.content.y + value * newBox.height;
|
|
26613
|
+
slideInBox.content.y = slideInContentY;
|
|
26614
|
+
slideOutBox.content.y = slideOutContentY;
|
|
26615
|
+
}
|
|
26616
|
+
slideOutBox.style.fillColor = slideInBox.style.fillColor = undefined;
|
|
26617
|
+
animatedBox.content = undefined;
|
|
26618
|
+
animatedBox.icons = iconLayoutChange ? {} : animatedBox.icons;
|
|
26619
|
+
return { newBoxes: [slideInBox, slideOutBox] };
|
|
26620
|
+
},
|
|
26621
|
+
});
|
|
26622
|
+
cellAnimationRegistry.add("borderFadeIn", {
|
|
26623
|
+
id: "borderFadeIn",
|
|
26624
|
+
easingFn: "easeInCubic",
|
|
26625
|
+
hasAnimation: (oldBox, newBox) => {
|
|
26626
|
+
return Boolean((!oldBox?.border?.bottom && newBox?.border?.bottom) ||
|
|
26627
|
+
(!oldBox?.border?.top && newBox?.border?.top) ||
|
|
26628
|
+
(!oldBox?.border?.left && newBox?.border?.left) ||
|
|
26629
|
+
(!oldBox?.border?.right && newBox?.border?.right));
|
|
26630
|
+
},
|
|
26631
|
+
updateAnimation: function (progress, animatedBox, oldBox, newBox) {
|
|
26632
|
+
const borderOpacity = EASING_FN[this.easingFn](progress);
|
|
26633
|
+
if (animatedBox.border?.top && newBox.border?.top && !oldBox.border?.top) {
|
|
26634
|
+
animatedBox.border.top.opacity = borderOpacity;
|
|
26635
|
+
}
|
|
26636
|
+
if (animatedBox.border?.bottom && newBox.border?.bottom && !oldBox.border?.bottom) {
|
|
26637
|
+
animatedBox.border.bottom.opacity = borderOpacity;
|
|
26638
|
+
}
|
|
26639
|
+
if (animatedBox.border?.left && newBox.border?.left && !oldBox.border?.left) {
|
|
26640
|
+
animatedBox.border.left.opacity = borderOpacity;
|
|
26641
|
+
}
|
|
26642
|
+
if (animatedBox.border?.right && newBox.border?.right && !oldBox.border?.right) {
|
|
26643
|
+
animatedBox.border.right.opacity = borderOpacity;
|
|
26644
|
+
}
|
|
26645
|
+
},
|
|
26646
|
+
});
|
|
26647
|
+
cellAnimationRegistry.add("borderFadeOut", {
|
|
26648
|
+
id: "borderFadeOut",
|
|
26649
|
+
easingFn: "easeOutCubic",
|
|
26650
|
+
hasAnimation: (oldBox, newBox) => {
|
|
26651
|
+
return Boolean((oldBox?.border?.bottom && !newBox?.border?.bottom) ||
|
|
26652
|
+
(oldBox?.border?.top && !newBox?.border?.top) ||
|
|
26653
|
+
(oldBox?.border?.left && !newBox?.border?.left) ||
|
|
26654
|
+
(oldBox?.border?.right && !newBox?.border?.right));
|
|
26655
|
+
},
|
|
26656
|
+
updateAnimation: function (progress, animatedBox, oldBox, newBox) {
|
|
26657
|
+
const borderOpacity = 1 - EASING_FN[this.easingFn](progress);
|
|
26658
|
+
if (!animatedBox.border) {
|
|
26659
|
+
animatedBox.border = {};
|
|
26660
|
+
}
|
|
26661
|
+
if (oldBox.border?.top && !newBox.border?.top) {
|
|
26662
|
+
animatedBox.border.top = { ...oldBox.border.top, opacity: borderOpacity };
|
|
26663
|
+
}
|
|
26664
|
+
if (oldBox.border?.bottom && !newBox.border?.bottom) {
|
|
26665
|
+
animatedBox.border.bottom = { ...oldBox.border.bottom, opacity: borderOpacity };
|
|
26666
|
+
}
|
|
26667
|
+
if (oldBox.border?.left && !newBox.border?.left) {
|
|
26668
|
+
animatedBox.border.left = { ...oldBox.border.left, opacity: borderOpacity };
|
|
26669
|
+
}
|
|
26670
|
+
if (oldBox.border?.right && !newBox.border?.right) {
|
|
26671
|
+
animatedBox.border.right = { ...oldBox.border.right, opacity: borderOpacity };
|
|
26672
|
+
}
|
|
26673
|
+
},
|
|
26674
|
+
});
|
|
26675
|
+
cellAnimationRegistry.add("borderColorChange", {
|
|
26676
|
+
id: "borderColorChange",
|
|
26677
|
+
easingFn: "easeOutCubic",
|
|
26678
|
+
hasAnimation: (oldBox, newBox) => {
|
|
26679
|
+
const oldBorder = oldBox?.border;
|
|
26680
|
+
const newBorder = newBox?.border;
|
|
26681
|
+
if (!oldBorder || !newBorder) {
|
|
26682
|
+
return false;
|
|
26683
|
+
}
|
|
26684
|
+
return Boolean(oldBorder.bottom?.color !== newBorder.bottom?.color ||
|
|
26685
|
+
oldBorder.top?.color !== newBorder.top?.color ||
|
|
26686
|
+
oldBorder.left?.color !== newBorder.left?.color ||
|
|
26687
|
+
oldBorder.right?.color !== newBorder.right?.color);
|
|
26688
|
+
},
|
|
26689
|
+
updateAnimation: function (progress, animatedBox, oldBox, newBox) {
|
|
26690
|
+
const animateBorderColor = (side) => {
|
|
26691
|
+
const oldBorder = oldBox?.border?.[side];
|
|
26692
|
+
const newBorder = newBox?.border?.[side];
|
|
26693
|
+
const animatedBorder = animatedBox.border?.[side];
|
|
26694
|
+
if (oldBorder && newBorder && animatedBorder) {
|
|
26695
|
+
const colorScale = getColorScale([
|
|
26696
|
+
{ value: 0, color: oldBorder.color || "#000000" },
|
|
26697
|
+
{ value: 1, color: newBorder.color || "#000000" },
|
|
26698
|
+
]);
|
|
26699
|
+
animatedBorder.color = colorScale(EASING_FN[this.easingFn](progress));
|
|
26700
|
+
}
|
|
26701
|
+
};
|
|
26702
|
+
animateBorderColor("top");
|
|
26703
|
+
animateBorderColor("bottom");
|
|
26704
|
+
animateBorderColor("left");
|
|
26705
|
+
animateBorderColor("right");
|
|
26706
|
+
},
|
|
26707
|
+
});
|
|
26708
|
+
cellAnimationRegistry.add("iconChange", {
|
|
26709
|
+
id: "iconChange",
|
|
26710
|
+
easingFn: "easeOutCubic",
|
|
26711
|
+
hasAnimation: (oldBox, newBox) => {
|
|
26712
|
+
return (!hasIconLayoutChange(newBox, oldBox) &&
|
|
26713
|
+
Boolean(oldBox?.icons?.center?.svg?.name !== newBox?.icons?.center?.svg?.name ||
|
|
26714
|
+
oldBox?.icons?.left?.svg?.name !== newBox?.icons?.left?.svg?.name ||
|
|
26715
|
+
oldBox?.icons?.right?.svg?.name !== newBox?.icons?.right?.svg?.name));
|
|
26716
|
+
},
|
|
26717
|
+
updateAnimation: function (progress, animatedBox, oldBox, newBox) {
|
|
26718
|
+
const value = EASING_FN[this.easingFn](progress);
|
|
26719
|
+
const slideInY = newBox.y + (value - 1) * newBox.height;
|
|
26720
|
+
const slideOutY = newBox.y + value * newBox.height;
|
|
26721
|
+
const newBoxes = [];
|
|
26722
|
+
const animateIconChange = (side) => {
|
|
26723
|
+
const oldIcon = oldBox.icons?.[side];
|
|
26724
|
+
const newIcon = newBox.icons?.[side];
|
|
26725
|
+
const slideInBox = {
|
|
26726
|
+
id: `${newBox.id}-icon-${side}-slide-in`,
|
|
26727
|
+
style: { verticalAlign: newBox.style.verticalAlign },
|
|
26728
|
+
x: newBox.x,
|
|
26729
|
+
y: slideInY,
|
|
26730
|
+
width: newBox.width,
|
|
26731
|
+
height: newBox.height,
|
|
26732
|
+
skipCellGridLines: true,
|
|
26733
|
+
icons: { [side]: { ...newIcon, clipRect: newBox } },
|
|
26734
|
+
};
|
|
26735
|
+
const slideOutBox = {
|
|
26736
|
+
id: `${newBox.id}-icon-${side}-slide-out`,
|
|
26737
|
+
style: { verticalAlign: oldBox.style.verticalAlign },
|
|
26738
|
+
x: newBox.x,
|
|
26739
|
+
y: slideOutY,
|
|
26740
|
+
width: newBox.width,
|
|
26741
|
+
height: newBox.height,
|
|
26742
|
+
skipCellGridLines: true,
|
|
26743
|
+
icons: { [side]: { ...oldIcon, clipRect: newBox } },
|
|
26744
|
+
};
|
|
26745
|
+
animatedBox.icons[side] = makeIconsEmpty(newBox.icons)[side];
|
|
26746
|
+
newBoxes.push(slideInBox, slideOutBox);
|
|
26747
|
+
};
|
|
26748
|
+
animateIconChange("left");
|
|
26749
|
+
animateIconChange("right");
|
|
26750
|
+
animateIconChange("center");
|
|
26751
|
+
return { newBoxes };
|
|
26752
|
+
},
|
|
26753
|
+
});
|
|
26754
|
+
const EASING_FN = {
|
|
26755
|
+
linear: (t) => t,
|
|
26756
|
+
easeInCubic: (t) => t * t * t,
|
|
26757
|
+
easeOutCubic: (t) => (t -= 1) * t * t + 1,
|
|
26758
|
+
easeInOutCubic: (t) => ((t /= 0.5) < 1 ? 0.5 * t * t * t : 0.5 * ((t -= 2) * t * t + 2)),
|
|
26759
|
+
easeOutQuart: (t) => -((t -= 1) * t * t * t - 1),
|
|
26760
|
+
};
|
|
26761
|
+
function makeIconsEmpty(icons) {
|
|
26762
|
+
return {
|
|
26763
|
+
left: icons.left ? { ...icons.left, svg: undefined } : undefined,
|
|
26764
|
+
right: icons.right ? { ...icons.right, svg: undefined } : undefined,
|
|
26765
|
+
center: icons.center ? { ...icons.center, svg: undefined } : undefined,
|
|
26766
|
+
};
|
|
26767
|
+
}
|
|
26768
|
+
function addClipRectToIcons(icons, clipRect) {
|
|
26769
|
+
return {
|
|
26770
|
+
left: icons.left ? { ...icons.left, clipRect } : undefined,
|
|
26771
|
+
right: icons.right ? { ...icons.right, clipRect } : undefined,
|
|
26772
|
+
center: icons.center ? { ...icons.center, clipRect } : undefined,
|
|
26773
|
+
};
|
|
26774
|
+
}
|
|
26775
|
+
/**
|
|
26776
|
+
* Check if the icons have appeared, disappeared or changed margin/size/align. Those changes affect where the text is positioned.
|
|
26777
|
+
*/
|
|
26778
|
+
function hasIconLayoutChange(newBox, oldBox) {
|
|
26779
|
+
const hasLayoutChange = (newIcon, oldIcon) => {
|
|
26780
|
+
if (oldIcon && newIcon) {
|
|
26781
|
+
return !!(newIcon.horizontalAlign !== oldIcon.horizontalAlign ||
|
|
26782
|
+
newIcon.size !== oldIcon.size ||
|
|
26783
|
+
newIcon.margin !== oldIcon.margin ||
|
|
26784
|
+
(newIcon.svg && !oldIcon.svg) ||
|
|
26785
|
+
(!newIcon.svg && oldIcon.svg));
|
|
26786
|
+
}
|
|
26787
|
+
return !!((newIcon && !oldIcon) || (!newIcon && oldIcon));
|
|
26788
|
+
};
|
|
26789
|
+
return (hasLayoutChange(newBox?.icons.left, oldBox?.icons.left) ||
|
|
26790
|
+
hasLayoutChange(newBox?.icons.right, oldBox?.icons.right) ||
|
|
26791
|
+
hasLayoutChange(newBox?.icons.center, oldBox?.icons.center));
|
|
26792
|
+
}
|
|
26793
|
+
|
|
26794
|
+
const ANIMATION_DURATION = 1000;
|
|
26331
26795
|
class GaugeChartComponent extends owl.Component {
|
|
26332
26796
|
static template = "o-spreadsheet-GaugeChartComponent";
|
|
26333
26797
|
static props = {
|
|
@@ -26335,16 +26799,101 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
26335
26799
|
isFullScreen: { type: Boolean, optional: true },
|
|
26336
26800
|
};
|
|
26337
26801
|
canvas = owl.useRef("chartContainer");
|
|
26802
|
+
animationStore;
|
|
26338
26803
|
get runtime() {
|
|
26339
26804
|
return this.env.model.getters.getChartRuntime(this.props.figureUI.id);
|
|
26340
26805
|
}
|
|
26341
26806
|
setup() {
|
|
26342
|
-
|
|
26343
|
-
|
|
26344
|
-
|
|
26807
|
+
if (this.env.model.getters.isDashboard()) {
|
|
26808
|
+
this.animationStore = useStore(ChartAnimationStore);
|
|
26809
|
+
}
|
|
26810
|
+
let animation = null;
|
|
26811
|
+
let lastRuntime = undefined;
|
|
26812
|
+
owl.useEffect(() => {
|
|
26813
|
+
if (this.env.isDashboard() &&
|
|
26814
|
+
lastRuntime === undefined && // first render
|
|
26815
|
+
this.animationStore?.animationPlayed[this.animationFigureId] !== "gauge") {
|
|
26816
|
+
animation = this.drawGaugeWithAnimation();
|
|
26817
|
+
this.animationStore?.disableAnimationForChart(this.animationFigureId, "gauge");
|
|
26818
|
+
}
|
|
26819
|
+
else if (this.env.isDashboard() &&
|
|
26820
|
+
lastRuntime !== undefined && // not first render
|
|
26821
|
+
!deepEquals(this.runtime, lastRuntime)) {
|
|
26822
|
+
animation = this.drawGaugeWithAnimation();
|
|
26823
|
+
this.animationStore?.disableAnimationForChart(this.animationFigureId, "gauge");
|
|
26824
|
+
}
|
|
26825
|
+
else {
|
|
26826
|
+
drawGaugeChart(this.canvasEl, this.runtime);
|
|
26827
|
+
}
|
|
26828
|
+
lastRuntime = this.runtime;
|
|
26829
|
+
return () => animation?.stop();
|
|
26830
|
+
}, () => {
|
|
26831
|
+
const rect = this.canvasEl.getBoundingClientRect();
|
|
26345
26832
|
return [rect.width, rect.height, this.runtime, this.canvas.el, window.devicePixelRatio];
|
|
26346
26833
|
});
|
|
26347
26834
|
}
|
|
26835
|
+
drawGaugeWithAnimation() {
|
|
26836
|
+
drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue: 0 });
|
|
26837
|
+
const gaugeValue = this.runtime.gaugeValue?.value || 0;
|
|
26838
|
+
const upperBound = this.runtime.maxValue.value;
|
|
26839
|
+
const finalValue = Math.sign(gaugeValue) * Math.min(Math.abs(gaugeValue), Math.abs(upperBound));
|
|
26840
|
+
if (finalValue === 0) {
|
|
26841
|
+
return null;
|
|
26842
|
+
}
|
|
26843
|
+
const lowerBound = this.runtime.minValue.value;
|
|
26844
|
+
const animation = new Animation(lowerBound, finalValue, ANIMATION_DURATION, (animationValue) => drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue }));
|
|
26845
|
+
animation.start();
|
|
26846
|
+
return animation;
|
|
26847
|
+
}
|
|
26848
|
+
get canvasEl() {
|
|
26849
|
+
return this.canvas.el;
|
|
26850
|
+
}
|
|
26851
|
+
get animationFigureId() {
|
|
26852
|
+
return this.props.isFullScreen
|
|
26853
|
+
? this.props.figureUI.id + "-fullscreen"
|
|
26854
|
+
: this.props.figureUI.id;
|
|
26855
|
+
}
|
|
26856
|
+
}
|
|
26857
|
+
/**
|
|
26858
|
+
* Animation interpolating values using the ease-out quartic curve function (chartJS default easing)
|
|
26859
|
+
*/
|
|
26860
|
+
class Animation {
|
|
26861
|
+
startValue;
|
|
26862
|
+
endValue;
|
|
26863
|
+
duration;
|
|
26864
|
+
callback;
|
|
26865
|
+
startTime = undefined;
|
|
26866
|
+
animationFrameId = null;
|
|
26867
|
+
constructor(startValue, endValue, duration, callback) {
|
|
26868
|
+
this.startValue = startValue;
|
|
26869
|
+
this.endValue = endValue;
|
|
26870
|
+
this.duration = duration;
|
|
26871
|
+
this.callback = callback;
|
|
26872
|
+
}
|
|
26873
|
+
start() {
|
|
26874
|
+
this.animationFrameId = requestAnimationFrame(this.animate.bind(this));
|
|
26875
|
+
}
|
|
26876
|
+
stop() {
|
|
26877
|
+
if (this.animationFrameId) {
|
|
26878
|
+
cancelAnimationFrame(this.animationFrameId);
|
|
26879
|
+
this.animationFrameId = null;
|
|
26880
|
+
}
|
|
26881
|
+
}
|
|
26882
|
+
animate(timestamp) {
|
|
26883
|
+
if (!this.startTime) {
|
|
26884
|
+
this.startTime = timestamp;
|
|
26885
|
+
}
|
|
26886
|
+
const elapsed = timestamp - this.startTime;
|
|
26887
|
+
const progress = Math.min(elapsed / this.duration, 1);
|
|
26888
|
+
const currentValue = this.startValue + (this.endValue - this.startValue) * EASING_FN.easeOutQuart(progress);
|
|
26889
|
+
this.callback(currentValue);
|
|
26890
|
+
if (progress < 1) {
|
|
26891
|
+
this.animationFrameId = requestAnimationFrame(this.animate.bind(this));
|
|
26892
|
+
}
|
|
26893
|
+
else {
|
|
26894
|
+
this.stop();
|
|
26895
|
+
}
|
|
26896
|
+
}
|
|
26348
26897
|
}
|
|
26349
26898
|
|
|
26350
26899
|
class ComboChart extends AbstractChart {
|
|
@@ -32160,7 +32709,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32160
32709
|
}
|
|
32161
32710
|
captureSelection(zone, col, row) {
|
|
32162
32711
|
this.model.selection.capture(this, {
|
|
32163
|
-
cell: { col: col
|
|
32712
|
+
cell: { col: col ?? zone.left, row: row ?? zone.right },
|
|
32164
32713
|
zone,
|
|
32165
32714
|
}, {
|
|
32166
32715
|
handleEvent: this.handleEvent.bind(this),
|
|
@@ -36537,6 +37086,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36537
37086
|
// We need here the svg of the icons that we need to convert to images for the renderer
|
|
36538
37087
|
// -----------------------------------------------------------------------------
|
|
36539
37088
|
const ARROW_DOWN = {
|
|
37089
|
+
name: "ARROW_DOWN",
|
|
36540
37090
|
width: 448,
|
|
36541
37091
|
height: 512,
|
|
36542
37092
|
paths: [
|
|
@@ -36547,6 +37097,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36547
37097
|
],
|
|
36548
37098
|
};
|
|
36549
37099
|
const ARROW_UP = {
|
|
37100
|
+
name: "ARROW_UP",
|
|
36550
37101
|
width: 448,
|
|
36551
37102
|
height: 512,
|
|
36552
37103
|
paths: [
|
|
@@ -36557,6 +37108,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36557
37108
|
],
|
|
36558
37109
|
};
|
|
36559
37110
|
const ARROW_RIGHT = {
|
|
37111
|
+
name: "ARROW_RIGHT",
|
|
36560
37112
|
width: 448,
|
|
36561
37113
|
height: 512,
|
|
36562
37114
|
paths: [
|
|
@@ -36567,6 +37119,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36567
37119
|
],
|
|
36568
37120
|
};
|
|
36569
37121
|
const SMILE = {
|
|
37122
|
+
name: "SMILE",
|
|
36570
37123
|
width: 496,
|
|
36571
37124
|
height: 512,
|
|
36572
37125
|
paths: [
|
|
@@ -36577,6 +37130,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36577
37130
|
],
|
|
36578
37131
|
};
|
|
36579
37132
|
const MEH = {
|
|
37133
|
+
name: "MEH",
|
|
36580
37134
|
width: 496,
|
|
36581
37135
|
height: 512,
|
|
36582
37136
|
paths: [
|
|
@@ -36587,6 +37141,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36587
37141
|
],
|
|
36588
37142
|
};
|
|
36589
37143
|
const FROWN = {
|
|
37144
|
+
name: "FROWN",
|
|
36590
37145
|
width: 496,
|
|
36591
37146
|
height: 512,
|
|
36592
37147
|
paths: [
|
|
@@ -36598,22 +37153,26 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36598
37153
|
};
|
|
36599
37154
|
const DOT_PATH = "M256 9 a247 247 0 1 0.1 0 0";
|
|
36600
37155
|
const GREEN_DOT = {
|
|
37156
|
+
name: "GREEN_DOT",
|
|
36601
37157
|
width: 512,
|
|
36602
37158
|
height: 512,
|
|
36603
37159
|
paths: [{ fillColor: "#6AA84F", path: DOT_PATH }],
|
|
36604
37160
|
};
|
|
36605
37161
|
const YELLOW_DOT = {
|
|
37162
|
+
name: "YELLOW_DOT",
|
|
36606
37163
|
width: 512,
|
|
36607
37164
|
height: 512,
|
|
36608
37165
|
paths: [{ fillColor: "#F0AD4E", path: DOT_PATH }],
|
|
36609
37166
|
};
|
|
36610
37167
|
const RED_DOT = {
|
|
37168
|
+
name: "RED_DOT",
|
|
36611
37169
|
width: 512,
|
|
36612
37170
|
height: 512,
|
|
36613
37171
|
paths: [{ fillColor: "#E06666", path: DOT_PATH }],
|
|
36614
37172
|
};
|
|
36615
37173
|
function getCaretDownSvg(color) {
|
|
36616
37174
|
return {
|
|
37175
|
+
name: "CARET_DOWN",
|
|
36617
37176
|
width: 512,
|
|
36618
37177
|
height: 512,
|
|
36619
37178
|
paths: [{ fillColor: color.textColor || TEXT_BODY_MUTED, path: "M120 195 h270 l-135 130" }],
|
|
@@ -36621,6 +37180,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36621
37180
|
}
|
|
36622
37181
|
function getHoveredCaretDownSvg(color) {
|
|
36623
37182
|
return {
|
|
37183
|
+
name: "CARET_DOWN",
|
|
36624
37184
|
width: 512,
|
|
36625
37185
|
height: 512,
|
|
36626
37186
|
paths: [
|
|
@@ -36632,6 +37192,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36632
37192
|
const CHIP_CARET_DOWN_PATH = "M40 185 h270 l-135 128";
|
|
36633
37193
|
function getChipSvg(chipStyle) {
|
|
36634
37194
|
return {
|
|
37195
|
+
name: "CHIP",
|
|
36635
37196
|
width: 512,
|
|
36636
37197
|
height: 512,
|
|
36637
37198
|
paths: [{ fillColor: chipStyle.textColor || TEXT_BODY_MUTED, path: CHIP_CARET_DOWN_PATH }],
|
|
@@ -36639,6 +37200,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36639
37200
|
}
|
|
36640
37201
|
function getHoveredChipSvg(chipStyle) {
|
|
36641
37202
|
return {
|
|
37203
|
+
name: "CHIP",
|
|
36642
37204
|
width: 512,
|
|
36643
37205
|
height: 512,
|
|
36644
37206
|
paths: [
|
|
@@ -36651,16 +37213,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36651
37213
|
};
|
|
36652
37214
|
}
|
|
36653
37215
|
const CHECKBOX_UNCHECKED = {
|
|
37216
|
+
name: "CHECKBOX_UNCHECKED",
|
|
36654
37217
|
width: 512,
|
|
36655
37218
|
height: 512,
|
|
36656
37219
|
paths: [{ fillColor: GRAY_300, path: "M45,45 h422 v422 h-422 v-422 m30,30 v362 h362 v-362" }],
|
|
36657
37220
|
};
|
|
36658
37221
|
const CHECKBOX_UNCHECKED_HOVERED = {
|
|
37222
|
+
name: "CHECKBOX_UNCHECKED",
|
|
36659
37223
|
width: 512,
|
|
36660
37224
|
height: 512,
|
|
36661
37225
|
paths: [{ fillColor: ACTION_COLOR, path: "M45,45 h422 v422 h-422 v-422 m30,30 v362 h362 v-362" }],
|
|
36662
37226
|
};
|
|
36663
37227
|
const CHECKBOX_CHECKED = {
|
|
37228
|
+
name: "CHECKBOX_CHECKED",
|
|
36664
37229
|
width: 512,
|
|
36665
37230
|
height: 512,
|
|
36666
37231
|
paths: [
|
|
@@ -36673,6 +37238,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36673
37238
|
? "M149,235 h213 v43 h-213 M235,149 h43 v213 h-43" // +
|
|
36674
37239
|
: "M149,235 h213 v43 h-213"; // -
|
|
36675
37240
|
return {
|
|
37241
|
+
name: "PIVOT_ICON",
|
|
36676
37242
|
width: 512,
|
|
36677
37243
|
height: 512,
|
|
36678
37244
|
paths: [
|
|
@@ -36699,6 +37265,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
36699
37265
|
colors.hoverBackgroundColor = "#fff";
|
|
36700
37266
|
}
|
|
36701
37267
|
return {
|
|
37268
|
+
name: "DATA_FILTER_ICON",
|
|
36702
37269
|
width: isActive ? 24 : 850,
|
|
36703
37270
|
height: isActive ? 24 : 850,
|
|
36704
37271
|
paths: [
|
|
@@ -40894,6 +41461,23 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
40894
41461
|
}
|
|
40895
41462
|
return data;
|
|
40896
41463
|
},
|
|
41464
|
+
})
|
|
41465
|
+
.add("18.4.3", {
|
|
41466
|
+
migrate(data) {
|
|
41467
|
+
if (!data.pivots) {
|
|
41468
|
+
return data;
|
|
41469
|
+
}
|
|
41470
|
+
for (const pivotId in data.pivots) {
|
|
41471
|
+
const pivot = data.pivots[pivotId];
|
|
41472
|
+
if (pivot.sortedColumn) {
|
|
41473
|
+
const measure = pivot.measures.find((measure) => measure.fieldName === pivot.sortedColumn?.measure);
|
|
41474
|
+
if (measure) {
|
|
41475
|
+
pivot.sortedColumn.measure = measure.id;
|
|
41476
|
+
}
|
|
41477
|
+
}
|
|
41478
|
+
}
|
|
41479
|
+
return data;
|
|
41480
|
+
},
|
|
40897
41481
|
});
|
|
40898
41482
|
function fixOverlappingFilters(data) {
|
|
40899
41483
|
for (const sheet of data.sheets || []) {
|
|
@@ -45960,15 +46544,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45960
46544
|
return state;
|
|
45961
46545
|
}
|
|
45962
46546
|
|
|
46547
|
+
const PAINT_FORMAT_HANDLER_KEYS = [
|
|
46548
|
+
"cell",
|
|
46549
|
+
"border",
|
|
46550
|
+
"table",
|
|
46551
|
+
"conditionalFormat",
|
|
46552
|
+
"merge",
|
|
46553
|
+
];
|
|
45963
46554
|
class PaintFormatStore extends SpreadsheetStore {
|
|
45964
46555
|
mutators = ["activate", "cancel", "pasteFormat"];
|
|
45965
46556
|
highlightStore = this.get(HighlightStore);
|
|
45966
|
-
clipboardHandlers = [
|
|
45967
|
-
new CellClipboardHandler(this.getters, this.model.dispatch),
|
|
45968
|
-
new BorderClipboardHandler(this.getters, this.model.dispatch),
|
|
45969
|
-
new TableClipboardHandler(this.getters, this.model.dispatch),
|
|
45970
|
-
new ConditionalFormatClipboardHandler(this.getters, this.model.dispatch),
|
|
45971
|
-
];
|
|
45972
46557
|
status = "inactive";
|
|
45973
46558
|
copiedData;
|
|
45974
46559
|
constructor(get) {
|
|
@@ -45999,24 +46584,38 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45999
46584
|
get isActive() {
|
|
46000
46585
|
return this.status !== "inactive";
|
|
46001
46586
|
}
|
|
46587
|
+
get clipboardHandlers() {
|
|
46588
|
+
return PAINT_FORMAT_HANDLER_KEYS.map((handlerName) => {
|
|
46589
|
+
const HandlerClass = clipboardHandlersRegistries.cellHandlers.get(handlerName);
|
|
46590
|
+
return {
|
|
46591
|
+
handlerName,
|
|
46592
|
+
handler: new HandlerClass(this.getters, this.model.dispatch),
|
|
46593
|
+
};
|
|
46594
|
+
});
|
|
46595
|
+
}
|
|
46002
46596
|
copyFormats() {
|
|
46003
46597
|
const sheetId = this.getters.getActiveSheetId();
|
|
46004
46598
|
const zones = this.getters.getSelectedZones();
|
|
46005
|
-
const copiedData = {};
|
|
46006
|
-
for (const handler of this.clipboardHandlers) {
|
|
46007
|
-
|
|
46599
|
+
const copiedData = { zones, sheetId };
|
|
46600
|
+
for (const { handlerName, handler } of this.clipboardHandlers) {
|
|
46601
|
+
const handlerResult = handler.copy(getClipboardDataPositions(sheetId, zones), false);
|
|
46602
|
+
if (handlerResult !== undefined) {
|
|
46603
|
+
copiedData[handlerName] = handlerResult;
|
|
46604
|
+
}
|
|
46008
46605
|
}
|
|
46009
46606
|
return copiedData;
|
|
46010
46607
|
}
|
|
46011
46608
|
paintFormat(sheetId, target) {
|
|
46012
|
-
if (this.copiedData) {
|
|
46013
|
-
|
|
46014
|
-
handler.paste({ zones: target, sheetId }, this.copiedData, {
|
|
46015
|
-
isCutOperation: false,
|
|
46016
|
-
pasteOption: "onlyFormat",
|
|
46017
|
-
});
|
|
46018
|
-
}
|
|
46609
|
+
if (!this.copiedData) {
|
|
46610
|
+
return;
|
|
46019
46611
|
}
|
|
46612
|
+
const options = {
|
|
46613
|
+
isCutOperation: false,
|
|
46614
|
+
pasteOption: "onlyFormat",
|
|
46615
|
+
};
|
|
46616
|
+
const { target: pasteTarget, selectedZones } = getPasteTargetFromHandlers(sheetId, target, this.copiedData, this.clipboardHandlers, options);
|
|
46617
|
+
applyClipboardHandlersPaste(this.clipboardHandlers, this.copiedData, pasteTarget, options);
|
|
46618
|
+
selectPastedZone(this.model.selection, target, selectedZones);
|
|
46020
46619
|
if (this.status === "oneOff") {
|
|
46021
46620
|
this.cancel();
|
|
46022
46621
|
}
|
|
@@ -46063,12 +46662,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46063
46662
|
this.row = undefined;
|
|
46064
46663
|
}
|
|
46065
46664
|
computeOverlay() {
|
|
46066
|
-
if (!this.getters.isDashboard()) {
|
|
46067
|
-
return;
|
|
46068
|
-
}
|
|
46069
46665
|
this.overlayColors = new PositionMap();
|
|
46070
|
-
const col = this
|
|
46071
|
-
const row = this.row;
|
|
46666
|
+
const { col, row } = this;
|
|
46072
46667
|
if (col === undefined || row === undefined) {
|
|
46073
46668
|
return;
|
|
46074
46669
|
}
|
|
@@ -46077,9 +46672,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46077
46672
|
if (!table) {
|
|
46078
46673
|
return;
|
|
46079
46674
|
}
|
|
46080
|
-
const { left, right } = table.range.zone;
|
|
46081
|
-
|
|
46082
|
-
|
|
46675
|
+
const { left, right, top } = table.range.zone;
|
|
46676
|
+
const isTableHeader = row < top + table.config.numberOfHeaders;
|
|
46677
|
+
const doesTableRowHaveContent = range(left, right + 1).some((col) => {
|
|
46678
|
+
return (!this.getters.isColHidden(sheetId, col) &&
|
|
46679
|
+
this.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
|
|
46680
|
+
});
|
|
46681
|
+
if (!isTableHeader && doesTableRowHaveContent) {
|
|
46682
|
+
for (let col = left; col <= right; col++) {
|
|
46683
|
+
this.overlayColors.set({ sheetId, col, row }, TABLE_HOVER_BACKGROUND_COLOR);
|
|
46684
|
+
}
|
|
46083
46685
|
}
|
|
46084
46686
|
}
|
|
46085
46687
|
}
|
|
@@ -46327,7 +46929,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46327
46929
|
}
|
|
46328
46930
|
const icons = this.env.model.getters.getCellIcons(position);
|
|
46329
46931
|
const icon = icons.find((icon) => {
|
|
46330
|
-
|
|
46932
|
+
const merge = this.env.model.getters.getMerge(position);
|
|
46933
|
+
const zone = merge || positionToZone(position);
|
|
46934
|
+
const cellRect = this.env.model.getters.getRect(zone);
|
|
46935
|
+
return isPointInsideRect(x, y, this.env.model.getters.getCellIconRect(icon, cellRect));
|
|
46331
46936
|
});
|
|
46332
46937
|
return icon?.onClick ? icon : undefined;
|
|
46333
46938
|
}
|
|
@@ -47064,19 +47669,56 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47064
47669
|
}
|
|
47065
47670
|
}
|
|
47066
47671
|
|
|
47067
|
-
|
|
47068
|
-
|
|
47069
|
-
renderer;
|
|
47672
|
+
const CELL_ANIMATION_DURATION = 200;
|
|
47673
|
+
class GridRenderer extends SpreadsheetStore {
|
|
47070
47674
|
fingerprints;
|
|
47071
47675
|
hoveredTables;
|
|
47072
47676
|
hoveredIcon;
|
|
47677
|
+
lastRenderBoxes = new Map();
|
|
47678
|
+
preventNewAnimationsInNextFrame = false;
|
|
47679
|
+
zonesWithPreventedAnimationsInNextFrame = [];
|
|
47680
|
+
animations = new Map();
|
|
47073
47681
|
constructor(get) {
|
|
47682
|
+
super(get);
|
|
47074
47683
|
this.getters = get(ModelStore).getters;
|
|
47075
|
-
this.renderer = get(RendererStore);
|
|
47076
47684
|
this.fingerprints = get(FormulaFingerprintStore);
|
|
47077
47685
|
this.hoveredTables = get(HoveredTableStore);
|
|
47078
47686
|
this.hoveredIcon = get(HoveredIconStore);
|
|
47079
|
-
|
|
47687
|
+
}
|
|
47688
|
+
handle(cmd) {
|
|
47689
|
+
switch (cmd.type) {
|
|
47690
|
+
case "START":
|
|
47691
|
+
case "ACTIVATE_SHEET":
|
|
47692
|
+
case "ADD_COLUMNS_ROWS":
|
|
47693
|
+
case "REMOVE_COLUMNS_ROWS":
|
|
47694
|
+
this.animations.clear();
|
|
47695
|
+
this.preventNewAnimationsInNextFrame = true;
|
|
47696
|
+
break;
|
|
47697
|
+
case "RESIZE_COLUMNS_ROWS":
|
|
47698
|
+
this.preventNewAnimationsInNextFrame = true;
|
|
47699
|
+
break;
|
|
47700
|
+
case "REDO":
|
|
47701
|
+
this.zonesWithPreventedAnimationsInNextFrame = [];
|
|
47702
|
+
break;
|
|
47703
|
+
case "UNDO":
|
|
47704
|
+
for (const command of cmd.commands) {
|
|
47705
|
+
if (command.type === "ADD_COLUMNS_ROWS" ||
|
|
47706
|
+
command.type === "REMOVE_COLUMNS_ROWS" ||
|
|
47707
|
+
command.type === "RESIZE_COLUMNS_ROWS") {
|
|
47708
|
+
this.animations.clear();
|
|
47709
|
+
this.preventNewAnimationsInNextFrame = true;
|
|
47710
|
+
break;
|
|
47711
|
+
}
|
|
47712
|
+
}
|
|
47713
|
+
break;
|
|
47714
|
+
case "PASTE":
|
|
47715
|
+
this.zonesWithPreventedAnimationsInNextFrame.push(...this.getters.getSelectedZones());
|
|
47716
|
+
break;
|
|
47717
|
+
case "UPDATE_CELL":
|
|
47718
|
+
const zones = this.getters.getCommandZones(cmd);
|
|
47719
|
+
this.zonesWithPreventedAnimationsInNextFrame.push(...zones);
|
|
47720
|
+
break;
|
|
47721
|
+
}
|
|
47080
47722
|
}
|
|
47081
47723
|
get renderingLayers() {
|
|
47082
47724
|
return ["Background", "Headers"];
|
|
@@ -47084,17 +47726,20 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47084
47726
|
// ---------------------------------------------------------------------------
|
|
47085
47727
|
// Grid rendering
|
|
47086
47728
|
// ---------------------------------------------------------------------------
|
|
47087
|
-
drawLayer(renderingContext, layer) {
|
|
47729
|
+
drawLayer(renderingContext, layer, timeStamp) {
|
|
47088
47730
|
switch (layer) {
|
|
47089
47731
|
case "Background":
|
|
47090
47732
|
this.drawGlobalBackground(renderingContext);
|
|
47733
|
+
const oldBoxes = this.lastRenderBoxes;
|
|
47734
|
+
this.lastRenderBoxes = new Map();
|
|
47091
47735
|
for (const { zone, rect } of this.getters.getAllActiveViewportsZonesAndRect()) {
|
|
47092
47736
|
const { ctx } = renderingContext;
|
|
47093
47737
|
ctx.save();
|
|
47094
47738
|
ctx.beginPath();
|
|
47095
47739
|
ctx.rect(rect.x, rect.y, rect.width, rect.height);
|
|
47096
47740
|
ctx.clip();
|
|
47097
|
-
const
|
|
47741
|
+
const boxesWithoutAnimations = this.getGridBoxes(zone);
|
|
47742
|
+
const boxes = this.getBoxesWithAnimations(boxesWithoutAnimations, oldBoxes, timeStamp);
|
|
47098
47743
|
this.drawBackground(renderingContext, boxes);
|
|
47099
47744
|
this.drawOverflowingCellBackground(renderingContext, boxes);
|
|
47100
47745
|
this.drawCellBackground(renderingContext, boxes);
|
|
@@ -47104,6 +47749,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47104
47749
|
ctx.restore();
|
|
47105
47750
|
}
|
|
47106
47751
|
this.drawFrozenPanes(renderingContext);
|
|
47752
|
+
this.preventNewAnimationsInNextFrame = false;
|
|
47753
|
+
this.zonesWithPreventedAnimationsInNextFrame = [];
|
|
47107
47754
|
break;
|
|
47108
47755
|
case "Headers":
|
|
47109
47756
|
if (!this.getters.isDashboard()) {
|
|
@@ -47127,6 +47774,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47127
47774
|
const inset = areGridLinesVisible ? 0.1 * thinLineWidth : 0;
|
|
47128
47775
|
if (areGridLinesVisible) {
|
|
47129
47776
|
for (const box of boxes) {
|
|
47777
|
+
if (box.skipCellGridLines)
|
|
47778
|
+
continue;
|
|
47130
47779
|
ctx.strokeStyle = CELL_BORDER_COLOR;
|
|
47131
47780
|
ctx.lineWidth = thinLineWidth;
|
|
47132
47781
|
ctx.strokeRect(box.x + inset, box.y + inset, box.width - 2 * inset, box.height - 2 * inset);
|
|
@@ -47234,7 +47883,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47234
47883
|
* each line and adding 1 pixel to the end of each line (depending on the direction of the
|
|
47235
47884
|
* line).
|
|
47236
47885
|
*/
|
|
47237
|
-
function drawBorder({ style,
|
|
47886
|
+
function drawBorder({ color, style, opacity }, x1, y1, x2, y2) {
|
|
47887
|
+
ctx.globalAlpha = opacity ?? 1;
|
|
47238
47888
|
ctx.strokeStyle = color;
|
|
47239
47889
|
switch (style) {
|
|
47240
47890
|
case "medium":
|
|
@@ -47282,6 +47932,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47282
47932
|
ctx.stroke();
|
|
47283
47933
|
ctx.lineWidth = 1;
|
|
47284
47934
|
ctx.setLineDash([]);
|
|
47935
|
+
ctx.globalAlpha = 1;
|
|
47285
47936
|
}
|
|
47286
47937
|
}
|
|
47287
47938
|
drawTexts(renderingContext, boxes) {
|
|
@@ -47290,6 +47941,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47290
47941
|
let currentFont;
|
|
47291
47942
|
for (const box of boxes) {
|
|
47292
47943
|
if (box.content) {
|
|
47944
|
+
ctx.globalAlpha = box.textOpacity ?? 1;
|
|
47293
47945
|
const style = box.style || {};
|
|
47294
47946
|
const align = box.content.align || "left";
|
|
47295
47947
|
// compute font and textColor
|
|
@@ -47320,6 +47972,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47320
47972
|
if (box.clipRect) {
|
|
47321
47973
|
ctx.restore();
|
|
47322
47974
|
}
|
|
47975
|
+
ctx.globalAlpha = 1;
|
|
47323
47976
|
}
|
|
47324
47977
|
}
|
|
47325
47978
|
}
|
|
@@ -47336,11 +47989,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47336
47989
|
continue;
|
|
47337
47990
|
}
|
|
47338
47991
|
ctx.save();
|
|
47992
|
+
ctx.globalAlpha = icon.opacity ?? 1;
|
|
47339
47993
|
ctx.beginPath();
|
|
47340
|
-
|
|
47994
|
+
const clipRect = icon.clipRect || box;
|
|
47995
|
+
ctx.rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
|
|
47341
47996
|
ctx.clip();
|
|
47342
47997
|
const iconSize = icon.size;
|
|
47343
|
-
const { x, y } = this.getters.getCellIconRect(icon);
|
|
47998
|
+
const { x, y } = this.getters.getCellIconRect(icon, box);
|
|
47344
47999
|
ctx.translate(x, y);
|
|
47345
48000
|
ctx.scale(iconSize / svg.width, iconSize / svg.height);
|
|
47346
48001
|
for (const path of svg.paths) {
|
|
@@ -47549,7 +48204,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47549
48204
|
const cell = this.getters.getEvaluatedCell(position);
|
|
47550
48205
|
const showFormula = this.getters.shouldShowFormulas();
|
|
47551
48206
|
const { x, y, width, height } = this.getters.getRect(zone);
|
|
47552
|
-
const { verticalAlign } = this.getters.getCellStyle(position);
|
|
47553
48207
|
const chipStyle = this.getters.getDataValidationChipStyle(position);
|
|
47554
48208
|
let style = this.getters.getCellComputedStyle(position);
|
|
47555
48209
|
if (this.fingerprints.isEnabled) {
|
|
@@ -47569,6 +48223,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47569
48223
|
center: iconsList.find((icon) => icon?.horizontalAlign === "center"),
|
|
47570
48224
|
};
|
|
47571
48225
|
const box = {
|
|
48226
|
+
id: zoneToXc(zone),
|
|
47572
48227
|
x,
|
|
47573
48228
|
y,
|
|
47574
48229
|
width,
|
|
@@ -47576,11 +48231,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47576
48231
|
border: this.getters.getCellComputedBorder(position) || undefined,
|
|
47577
48232
|
style,
|
|
47578
48233
|
dataBarFill,
|
|
47579
|
-
verticalAlign,
|
|
47580
48234
|
overlayColor: this.hoveredTables.overlayColors.get(position),
|
|
47581
48235
|
isError: (cell.type === CellValueType.error && !!cell.message) ||
|
|
47582
48236
|
this.getters.isDataValidationInvalid(position),
|
|
47583
48237
|
icons: cellIcons,
|
|
48238
|
+
disabledAnimation: this.zonesWithPreventedAnimationsInNextFrame.some((z) => isZoneInside(zone, z) || overlap(zone, z)),
|
|
47584
48239
|
};
|
|
47585
48240
|
const fontSizePX = computeTextFontSizeInPixels(box.style);
|
|
47586
48241
|
if (cell.type === CellValueType.empty || box.icons.center) {
|
|
@@ -47750,6 +48405,77 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47750
48405
|
}
|
|
47751
48406
|
return boxes;
|
|
47752
48407
|
}
|
|
48408
|
+
getBoxesWithAnimations(boxes, oldBoxes, timeStamp) {
|
|
48409
|
+
this.updateAnimationsProgress(timeStamp);
|
|
48410
|
+
this.addNewAnimations(boxes, oldBoxes, timeStamp);
|
|
48411
|
+
if (this.animations.size > 0) {
|
|
48412
|
+
this.renderer.startAnimation("grid_renderer_animation");
|
|
48413
|
+
return this.updateBoxesWithAnimations(boxes);
|
|
48414
|
+
}
|
|
48415
|
+
else {
|
|
48416
|
+
this.renderer.stopAnimation("grid_renderer_animation");
|
|
48417
|
+
return boxes;
|
|
48418
|
+
}
|
|
48419
|
+
}
|
|
48420
|
+
updateBoxesWithAnimations(boxes) {
|
|
48421
|
+
const boxesWithAnimations = [];
|
|
48422
|
+
for (const box of boxes) {
|
|
48423
|
+
const animation = this.animations.get(box.id);
|
|
48424
|
+
if (!animation) {
|
|
48425
|
+
boxesWithAnimations.push(box);
|
|
48426
|
+
continue;
|
|
48427
|
+
}
|
|
48428
|
+
const animatedBox = deepCopy(box);
|
|
48429
|
+
boxesWithAnimations.push(animatedBox);
|
|
48430
|
+
for (const animationId of animation.animationTypes) {
|
|
48431
|
+
const animationItem = cellAnimationRegistry.get(animationId);
|
|
48432
|
+
const newBoxes = animationItem.updateAnimation(animation.progress, animatedBox, animation.oldBox, box);
|
|
48433
|
+
if (newBoxes) {
|
|
48434
|
+
boxesWithAnimations.push(...newBoxes.newBoxes);
|
|
48435
|
+
}
|
|
48436
|
+
}
|
|
48437
|
+
}
|
|
48438
|
+
return boxesWithAnimations;
|
|
48439
|
+
}
|
|
48440
|
+
updateAnimationsProgress(timeStamp) {
|
|
48441
|
+
if (timeStamp === undefined) {
|
|
48442
|
+
return;
|
|
48443
|
+
}
|
|
48444
|
+
for (const boxId of this.animations.keys()) {
|
|
48445
|
+
const animation = this.animations.get(boxId);
|
|
48446
|
+
if (animation.startTime === undefined) {
|
|
48447
|
+
animation.startTime = timeStamp;
|
|
48448
|
+
continue;
|
|
48449
|
+
}
|
|
48450
|
+
const elapsedTime = timeStamp - animation.startTime;
|
|
48451
|
+
const progress = Math.min(1, elapsedTime / CELL_ANIMATION_DURATION);
|
|
48452
|
+
if (progress >= 1) {
|
|
48453
|
+
this.animations.delete(boxId);
|
|
48454
|
+
}
|
|
48455
|
+
animation.progress = progress;
|
|
48456
|
+
}
|
|
48457
|
+
}
|
|
48458
|
+
addNewAnimations(boxes, oldBoxes, timeStamp) {
|
|
48459
|
+
for (const box of boxes) {
|
|
48460
|
+
this.lastRenderBoxes.set(box.id, box);
|
|
48461
|
+
const oldBox = oldBoxes.get(box.id);
|
|
48462
|
+
if (this.preventNewAnimationsInNextFrame || !oldBox || box.disabledAnimation) {
|
|
48463
|
+
continue;
|
|
48464
|
+
}
|
|
48465
|
+
const animationTypes = [];
|
|
48466
|
+
for (const animationItem of cellAnimationRegistry.getAll()) {
|
|
48467
|
+
if (animationItem.hasAnimation(oldBox, box)) {
|
|
48468
|
+
animationTypes.push(animationItem.id);
|
|
48469
|
+
}
|
|
48470
|
+
}
|
|
48471
|
+
const animation = animationTypes.length > 0
|
|
48472
|
+
? { animationTypes, oldBox, progress: 0, startTime: timeStamp }
|
|
48473
|
+
: undefined;
|
|
48474
|
+
if (animation) {
|
|
48475
|
+
this.animations.set(box.id, animation);
|
|
48476
|
+
}
|
|
48477
|
+
}
|
|
48478
|
+
}
|
|
47753
48479
|
}
|
|
47754
48480
|
|
|
47755
48481
|
function useGridDrawing(refName, model, canvasSize) {
|
|
@@ -47784,10 +48510,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47784
48510
|
// http://diveintohtml5.info/canvas.html#pixel-madness
|
|
47785
48511
|
ctx.translate(-CANVAS_SHIFT, -CANVAS_SHIFT);
|
|
47786
48512
|
ctx.scale(dpr, dpr);
|
|
47787
|
-
|
|
47788
|
-
model.drawLayer(renderingContext, layer);
|
|
47789
|
-
rendererStore.drawLayer(renderingContext, layer);
|
|
47790
|
-
}
|
|
48513
|
+
rendererStore.draw(renderingContext);
|
|
47791
48514
|
}
|
|
47792
48515
|
}
|
|
47793
48516
|
|
|
@@ -51655,6 +52378,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51655
52378
|
this.switchToList();
|
|
51656
52379
|
}
|
|
51657
52380
|
}
|
|
52381
|
+
else if (!this.editedCF) {
|
|
52382
|
+
this.switchToList();
|
|
52383
|
+
}
|
|
51658
52384
|
});
|
|
51659
52385
|
}
|
|
51660
52386
|
get conditionalFormats() {
|
|
@@ -54882,7 +55608,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54882
55608
|
}
|
|
54883
55609
|
getTypeFromZone(sheetId, zone) {
|
|
54884
55610
|
const cells = this.getters.getEvaluatedCellsInZone(sheetId, zone);
|
|
54885
|
-
const nonEmptyCells = cells.filter((cell) => cell.type
|
|
55611
|
+
const nonEmptyCells = cells.filter((cell) => !(cell.type === CellValueType.empty || cell.value === ""));
|
|
54886
55612
|
if (nonEmptyCells.length === 0) {
|
|
54887
55613
|
return "integer";
|
|
54888
55614
|
}
|
|
@@ -55490,7 +56216,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55490
56216
|
`;
|
|
55491
56217
|
class SettingsPanel extends owl.Component {
|
|
55492
56218
|
static template = "o-spreadsheet-SettingsPanel";
|
|
55493
|
-
static components = { Section, ValidationMessages };
|
|
56219
|
+
static components = { Section, ValidationMessages, BadgeSelection };
|
|
55494
56220
|
static props = { onCloseSidePanel: Function };
|
|
55495
56221
|
loadedLocales = [];
|
|
55496
56222
|
setup() {
|
|
@@ -56374,49 +57100,111 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56374
57100
|
}
|
|
56375
57101
|
|
|
56376
57102
|
const DEFAULT_SIDE_PANEL_SIZE = 350;
|
|
57103
|
+
const COLLAPSED_SIDE_PANEL_SIZE = 45;
|
|
56377
57104
|
const MIN_SHEET_VIEW_WIDTH = 150;
|
|
56378
57105
|
class SidePanelStore extends SpreadsheetStore {
|
|
56379
|
-
mutators = [
|
|
56380
|
-
|
|
56381
|
-
|
|
56382
|
-
|
|
57106
|
+
mutators = [
|
|
57107
|
+
"open",
|
|
57108
|
+
"toggle",
|
|
57109
|
+
"close",
|
|
57110
|
+
"changePanelSize",
|
|
57111
|
+
"resetPanelSize",
|
|
57112
|
+
"togglePinPanel",
|
|
57113
|
+
"closeMainPanel",
|
|
57114
|
+
"changeSpreadsheetWidth",
|
|
57115
|
+
"toggleCollapsePanel",
|
|
57116
|
+
];
|
|
57117
|
+
mainPanel = undefined;
|
|
57118
|
+
secondaryPanel;
|
|
57119
|
+
availableWidth = 0;
|
|
56383
57120
|
screenWidthStore = this.get(ScreenWidthStore);
|
|
56384
|
-
get
|
|
56385
|
-
|
|
56386
|
-
|
|
56387
|
-
|
|
56388
|
-
|
|
57121
|
+
get isMainPanelOpen() {
|
|
57122
|
+
return this.mainPanel && this.mainPanel.componentTag
|
|
57123
|
+
? this.computeState(this.mainPanel).isOpen
|
|
57124
|
+
: false;
|
|
57125
|
+
}
|
|
57126
|
+
get isSecondaryPanelOpen() {
|
|
57127
|
+
return this.secondaryPanel && this.secondaryPanel.componentTag
|
|
57128
|
+
? this.computeState(this.secondaryPanel).isOpen
|
|
57129
|
+
: false;
|
|
56389
57130
|
}
|
|
56390
|
-
get
|
|
56391
|
-
|
|
57131
|
+
get mainPanelProps() {
|
|
57132
|
+
return this.mainPanel ? this.getPanelProps(this.mainPanel) : undefined;
|
|
57133
|
+
}
|
|
57134
|
+
get mainPanelKey() {
|
|
57135
|
+
return this.mainPanel ? this.getPanelKey(this.mainPanel) : undefined;
|
|
57136
|
+
}
|
|
57137
|
+
get secondaryPanelProps() {
|
|
57138
|
+
return this.secondaryPanel ? this.getPanelProps(this.secondaryPanel) : undefined;
|
|
57139
|
+
}
|
|
57140
|
+
get secondaryPanelKey() {
|
|
57141
|
+
return this.secondaryPanel ? this.getPanelKey(this.secondaryPanel) : undefined;
|
|
57142
|
+
}
|
|
57143
|
+
get totalPanelSize() {
|
|
57144
|
+
return (this.mainPanel?.size || 0) + (this.secondaryPanel?.size ?? 0);
|
|
57145
|
+
}
|
|
57146
|
+
getPanelProps(panelInfo) {
|
|
57147
|
+
const state = this.computeState(panelInfo);
|
|
56392
57148
|
if (state.isOpen) {
|
|
56393
57149
|
return state.props ?? {};
|
|
56394
57150
|
}
|
|
56395
57151
|
return {};
|
|
56396
57152
|
}
|
|
56397
|
-
|
|
56398
|
-
const state = this.computeState(
|
|
57153
|
+
getPanelKey(panelInfo) {
|
|
57154
|
+
const state = this.computeState(panelInfo);
|
|
56399
57155
|
if (state.isOpen) {
|
|
56400
57156
|
return state.key;
|
|
56401
57157
|
}
|
|
56402
57158
|
return undefined;
|
|
56403
57159
|
}
|
|
56404
|
-
open(componentTag,
|
|
57160
|
+
open(componentTag, initialPanelProps = {}) {
|
|
56405
57161
|
if (this.screenWidthStore.isSmall) {
|
|
56406
57162
|
return;
|
|
56407
57163
|
}
|
|
56408
|
-
const
|
|
57164
|
+
const newPanelInfo = { initialPanelProps, componentTag, size: DEFAULT_SIDE_PANEL_SIZE };
|
|
57165
|
+
const state = this.computeState(newPanelInfo);
|
|
56409
57166
|
if (!state.isOpen) {
|
|
56410
57167
|
return;
|
|
56411
57168
|
}
|
|
56412
|
-
|
|
56413
|
-
|
|
57169
|
+
const mainPanelKey = this.mainPanel ? this.getPanelKey(this.mainPanel) : undefined;
|
|
57170
|
+
if (!this.mainPanel || !this.mainPanel.isPinned || mainPanelKey === state.key) {
|
|
57171
|
+
this._openPanel("mainPanel", newPanelInfo, state);
|
|
57172
|
+
return;
|
|
57173
|
+
}
|
|
57174
|
+
// Try to open secondary panel if main panel is pinned
|
|
57175
|
+
const nonCollapsedPanelSize = this.mainPanel.isCollapsed
|
|
57176
|
+
? DEFAULT_SIDE_PANEL_SIZE
|
|
57177
|
+
: this.mainPanel.size;
|
|
57178
|
+
if (!this.secondaryPanel &&
|
|
57179
|
+
nonCollapsedPanelSize + DEFAULT_SIDE_PANEL_SIZE > this.availableWidth) {
|
|
57180
|
+
this.get(NotificationStore).notifyUser({
|
|
57181
|
+
sticky: false,
|
|
57182
|
+
type: "warning",
|
|
57183
|
+
text: _t("The window is too small to display multiple side panels."),
|
|
57184
|
+
});
|
|
57185
|
+
return;
|
|
57186
|
+
}
|
|
57187
|
+
this._openPanel("secondaryPanel", newPanelInfo, state);
|
|
57188
|
+
}
|
|
57189
|
+
_openPanel(panel, newPanel, state) {
|
|
57190
|
+
const currentPanel = this[panel];
|
|
57191
|
+
if (currentPanel && newPanel.componentTag !== currentPanel.componentTag) {
|
|
57192
|
+
currentPanel.initialPanelProps?.onCloseSidePanel?.();
|
|
57193
|
+
}
|
|
57194
|
+
this[panel] = {
|
|
57195
|
+
initialPanelProps: state.props ?? {},
|
|
57196
|
+
componentTag: newPanel.componentTag,
|
|
57197
|
+
size: currentPanel?.size || DEFAULT_SIDE_PANEL_SIZE,
|
|
57198
|
+
isCollapsed: currentPanel?.isCollapsed || false,
|
|
57199
|
+
isPinned: currentPanel && "isPinned" in currentPanel ? currentPanel.isPinned : false,
|
|
57200
|
+
};
|
|
57201
|
+
if (this[panel].isCollapsed) {
|
|
57202
|
+
this.toggleCollapsePanel(panel);
|
|
56414
57203
|
}
|
|
56415
|
-
this.componentTag = componentTag;
|
|
56416
|
-
this.initialPanelProps = state.props ?? {};
|
|
56417
57204
|
}
|
|
56418
57205
|
toggle(componentTag, panelProps) {
|
|
56419
|
-
|
|
57206
|
+
const panel = this.mainPanel?.isPinned ? this.secondaryPanel : this.mainPanel;
|
|
57207
|
+
if (panel && componentTag === panel.componentTag) {
|
|
56420
57208
|
this.close();
|
|
56421
57209
|
}
|
|
56422
57210
|
else {
|
|
@@ -56424,34 +57212,85 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56424
57212
|
}
|
|
56425
57213
|
}
|
|
56426
57214
|
close() {
|
|
56427
|
-
this.
|
|
56428
|
-
|
|
56429
|
-
|
|
57215
|
+
if (this.mainPanel?.isPinned) {
|
|
57216
|
+
if (this.secondaryPanel) {
|
|
57217
|
+
this.secondaryPanel.initialPanelProps.onCloseSidePanel?.();
|
|
57218
|
+
this.secondaryPanel = undefined;
|
|
57219
|
+
}
|
|
57220
|
+
return;
|
|
57221
|
+
}
|
|
57222
|
+
this.mainPanel?.initialPanelProps.onCloseSidePanel?.();
|
|
57223
|
+
this.mainPanel = undefined;
|
|
56430
57224
|
}
|
|
56431
|
-
|
|
56432
|
-
|
|
56433
|
-
|
|
57225
|
+
closeMainPanel() {
|
|
57226
|
+
this.mainPanel?.initialPanelProps.onCloseSidePanel?.();
|
|
57227
|
+
this.mainPanel = this.secondaryPanel || undefined;
|
|
57228
|
+
this.secondaryPanel = undefined;
|
|
57229
|
+
}
|
|
57230
|
+
changePanelSize(panel, size) {
|
|
57231
|
+
const panelInfo = this[panel];
|
|
57232
|
+
if (!panelInfo || ("isCollapsed" in panelInfo && panelInfo.isCollapsed)) {
|
|
57233
|
+
return;
|
|
56434
57234
|
}
|
|
56435
|
-
|
|
56436
|
-
|
|
57235
|
+
size = Math.max(size, DEFAULT_SIDE_PANEL_SIZE);
|
|
57236
|
+
let otherPanelSize = panel === "mainPanel" ? this.secondaryPanel?.size || 0 : this.mainPanel?.size || 0;
|
|
57237
|
+
if (size > this.availableWidth - otherPanelSize) {
|
|
57238
|
+
if (panel === "mainPanel" && this.secondaryPanel) {
|
|
57239
|
+
// reduce the secondary panel size to fit the main panel
|
|
57240
|
+
this.secondaryPanel.size = Math.max(this.availableWidth - size, DEFAULT_SIDE_PANEL_SIZE);
|
|
57241
|
+
otherPanelSize = this.secondaryPanel.size;
|
|
57242
|
+
}
|
|
57243
|
+
size = Math.max(this.availableWidth - otherPanelSize, DEFAULT_SIDE_PANEL_SIZE);
|
|
56437
57244
|
}
|
|
56438
|
-
|
|
56439
|
-
|
|
57245
|
+
panelInfo.size = size;
|
|
57246
|
+
}
|
|
57247
|
+
resetPanelSize(panel) {
|
|
57248
|
+
const panelInfo = this[panel];
|
|
57249
|
+
if (!panelInfo) {
|
|
57250
|
+
return;
|
|
56440
57251
|
}
|
|
57252
|
+
panelInfo.size = DEFAULT_SIDE_PANEL_SIZE;
|
|
56441
57253
|
}
|
|
56442
|
-
|
|
56443
|
-
this.
|
|
57254
|
+
togglePinPanel() {
|
|
57255
|
+
if (!this.mainPanel) {
|
|
57256
|
+
return;
|
|
57257
|
+
}
|
|
57258
|
+
this.mainPanel.isPinned = !this.mainPanel.isPinned;
|
|
57259
|
+
if (!this.mainPanel.isPinned && this.secondaryPanel) {
|
|
57260
|
+
this.secondaryPanel?.initialPanelProps.onCloseSidePanel?.();
|
|
57261
|
+
this.mainPanel = this.secondaryPanel;
|
|
57262
|
+
this.secondaryPanel = undefined;
|
|
57263
|
+
}
|
|
56444
57264
|
}
|
|
56445
|
-
|
|
56446
|
-
const
|
|
56447
|
-
if (!
|
|
56448
|
-
return
|
|
56449
|
-
|
|
56450
|
-
|
|
56451
|
-
|
|
57265
|
+
toggleCollapsePanel(panel) {
|
|
57266
|
+
const panelInfo = this[panel];
|
|
57267
|
+
if (!panelInfo) {
|
|
57268
|
+
return;
|
|
57269
|
+
}
|
|
57270
|
+
if (panelInfo.isCollapsed) {
|
|
57271
|
+
panelInfo.isCollapsed = false;
|
|
57272
|
+
this.changePanelSize(panel, DEFAULT_SIDE_PANEL_SIZE);
|
|
56452
57273
|
}
|
|
56453
57274
|
else {
|
|
56454
|
-
|
|
57275
|
+
panelInfo.isCollapsed = true;
|
|
57276
|
+
panelInfo.size = COLLAPSED_SIDE_PANEL_SIZE;
|
|
57277
|
+
}
|
|
57278
|
+
}
|
|
57279
|
+
computeState({ componentTag, initialPanelProps }) {
|
|
57280
|
+
const customComputeState = sidePanelRegistry.get(componentTag).computeState;
|
|
57281
|
+
const state = customComputeState
|
|
57282
|
+
? customComputeState(this.getters, initialPanelProps)
|
|
57283
|
+
: { isOpen: true, props: initialPanelProps };
|
|
57284
|
+
return state.isOpen ? { ...state, key: state.key || componentTag } : state;
|
|
57285
|
+
}
|
|
57286
|
+
changeSpreadsheetWidth(width) {
|
|
57287
|
+
this.availableWidth = width - MIN_SHEET_VIEW_WIDTH;
|
|
57288
|
+
if (this.secondaryPanel && width - this.totalPanelSize < MIN_SHEET_VIEW_WIDTH) {
|
|
57289
|
+
this.secondaryPanel?.initialPanelProps.onCloseSidePanel?.();
|
|
57290
|
+
this.secondaryPanel = undefined;
|
|
57291
|
+
}
|
|
57292
|
+
if (this.mainPanel && width - this.totalPanelSize < MIN_SHEET_VIEW_WIDTH) {
|
|
57293
|
+
this.mainPanel.size = Math.max(width - MIN_SHEET_VIEW_WIDTH, DEFAULT_SIDE_PANEL_SIZE);
|
|
56455
57294
|
}
|
|
56456
57295
|
}
|
|
56457
57296
|
}
|
|
@@ -56599,11 +57438,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56599
57438
|
this.hoveredCell.clear();
|
|
56600
57439
|
});
|
|
56601
57440
|
this.cellPopovers = useStore(CellPopoverStore);
|
|
56602
|
-
owl.useEffect(() => {
|
|
56603
|
-
if (!
|
|
57441
|
+
owl.useEffect((isMainPanelOpen, isSecondaryPanelOpen) => {
|
|
57442
|
+
if (!isMainPanelOpen && !isSecondaryPanelOpen) {
|
|
56604
57443
|
this.DOMFocusableElementStore.focus();
|
|
56605
57444
|
}
|
|
56606
|
-
}, () => [this.sidePanel.
|
|
57445
|
+
}, () => [this.sidePanel.isMainPanelOpen, this.sidePanel.isSecondaryPanelOpen]);
|
|
56607
57446
|
useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
|
|
56608
57447
|
const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
56609
57448
|
return scrollY > 0;
|
|
@@ -59695,7 +60534,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
59695
60534
|
else if (newRule.criterion.type === "isValueInList") {
|
|
59696
60535
|
newRule.criterion.values = Array.from(new Set(newRule.criterion.values));
|
|
59697
60536
|
}
|
|
59698
|
-
const adaptedRules = this.removeRangesFromRules(sheetId, newRule.ranges, rules);
|
|
60537
|
+
const adaptedRules = this.removeRangesFromRules(sheetId, newRule.ranges, rules, newRule.id);
|
|
59699
60538
|
const ruleIndex = adaptedRules.findIndex((rule) => rule.id === newRule.id);
|
|
59700
60539
|
if (ruleIndex !== -1) {
|
|
59701
60540
|
adaptedRules[ruleIndex] = newRule;
|
|
@@ -59705,9 +60544,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
59705
60544
|
this.history.update("rules", sheetId, [...adaptedRules, newRule]);
|
|
59706
60545
|
}
|
|
59707
60546
|
}
|
|
59708
|
-
removeRangesFromRules(sheetId, ranges, rules) {
|
|
60547
|
+
removeRangesFromRules(sheetId, ranges, rules, editingRuleId) {
|
|
59709
60548
|
rules = deepCopy(rules);
|
|
59710
60549
|
for (const rule of rules) {
|
|
60550
|
+
if (rule.id === editingRuleId) {
|
|
60551
|
+
continue; // Skip the rule being edited to preserve its place in the list
|
|
60552
|
+
}
|
|
59711
60553
|
rule.ranges = this.getters.recomputeRanges(rule.ranges, ranges);
|
|
59712
60554
|
}
|
|
59713
60555
|
return rules.filter((rule) => rule.ranges.length > 0);
|
|
@@ -63115,7 +63957,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
63115
63957
|
break;
|
|
63116
63958
|
}
|
|
63117
63959
|
case "UPDATE_PIVOT": {
|
|
63118
|
-
this.history.update("pivots", cmd.pivotId, "definition",
|
|
63960
|
+
this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
|
|
63119
63961
|
this.compileCalculatedMeasures(cmd.pivot.measures);
|
|
63120
63962
|
break;
|
|
63121
63963
|
}
|
|
@@ -63186,10 +64028,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
63186
64028
|
// Private
|
|
63187
64029
|
// -------------------------------------------------------------------------
|
|
63188
64030
|
addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
|
|
63189
|
-
this.history.update("pivots", pivotId, {
|
|
63190
|
-
definition: this.repairSortedColumn(deepCopy(pivot)),
|
|
63191
|
-
formulaId,
|
|
63192
|
-
});
|
|
64031
|
+
this.history.update("pivots", pivotId, { definition: deepCopy(pivot), formulaId });
|
|
63193
64032
|
this.compileCalculatedMeasures(pivot.measures);
|
|
63194
64033
|
this.history.update("formulaIds", formulaId, pivotId);
|
|
63195
64034
|
this.history.update("nextFormulaId", this.nextFormulaId + 1);
|
|
@@ -63278,7 +64117,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
63278
64117
|
}
|
|
63279
64118
|
}
|
|
63280
64119
|
checkSortedColumnInMeasures(definition) {
|
|
63281
|
-
definition = this.repairSortedColumn(definition);
|
|
63282
64120
|
const measures = definition.measures.map((measure) => measure.id);
|
|
63283
64121
|
if (definition.sortedColumn && !measures.includes(definition.sortedColumn.measure)) {
|
|
63284
64122
|
return "InvalidDefinition" /* CommandResult.InvalidDefinition */;
|
|
@@ -63292,26 +64130,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
63292
64130
|
}
|
|
63293
64131
|
return "Success" /* CommandResult.Success */;
|
|
63294
64132
|
}
|
|
63295
|
-
repairSortedColumn(definition) {
|
|
63296
|
-
if (definition.sortedColumn) {
|
|
63297
|
-
// Fix for an upgrade issue: the sortedColumn measure was not updated
|
|
63298
|
-
// from using fieldName to using id. If the sortedColumn measure matches
|
|
63299
|
-
// a measure fieldName in the definition, update it to use the measure's id instead
|
|
63300
|
-
// of its fieldName.
|
|
63301
|
-
// TODO: add an upgrade step to fix this in master and remove this code
|
|
63302
|
-
const sortedMeasure = definition.measures.find((measure) => measure.fieldName === definition.sortedColumn?.measure);
|
|
63303
|
-
if (sortedMeasure) {
|
|
63304
|
-
return {
|
|
63305
|
-
...definition,
|
|
63306
|
-
sortedColumn: {
|
|
63307
|
-
...definition.sortedColumn,
|
|
63308
|
-
measure: sortedMeasure.id,
|
|
63309
|
-
},
|
|
63310
|
-
};
|
|
63311
|
-
}
|
|
63312
|
-
}
|
|
63313
|
-
return definition;
|
|
63314
|
-
}
|
|
63315
64133
|
// ---------------------------------------------------------------------
|
|
63316
64134
|
// Import/Export
|
|
63317
64135
|
// ---------------------------------------------------------------------
|
|
@@ -63393,9 +64211,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
63393
64211
|
this.locale = data.settings?.locale ?? DEFAULT_LOCALE;
|
|
63394
64212
|
}
|
|
63395
64213
|
export(data) {
|
|
63396
|
-
data.settings = {
|
|
63397
|
-
locale: this.locale,
|
|
63398
|
-
};
|
|
64214
|
+
data.settings = { locale: this.locale };
|
|
63399
64215
|
}
|
|
63400
64216
|
}
|
|
63401
64217
|
|
|
@@ -66430,11 +67246,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
66430
67246
|
}
|
|
66431
67247
|
return this.cellIconsCache[position.sheetId][position.col][position.row];
|
|
66432
67248
|
}
|
|
66433
|
-
getCellIconRect(icon) {
|
|
67249
|
+
getCellIconRect(icon, cellRect) {
|
|
66434
67250
|
const cellPosition = icon.position;
|
|
66435
|
-
const merge = this.getters.getMerge(cellPosition);
|
|
66436
|
-
const zone = merge || positionToZone(cellPosition);
|
|
66437
|
-
const cellRect = this.getters.getRect(zone);
|
|
66438
67251
|
const cell = this.getters.getCell(cellPosition);
|
|
66439
67252
|
const x = this.getIconHorizontalPosition(cellRect, icon.horizontalAlign, icon);
|
|
66440
67253
|
const y = this.getters.computeTextYCoordinate(cellRect, icon.size, cell?.style?.verticalAlign);
|
|
@@ -72267,49 +73080,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
72267
73080
|
if (!copiedData) {
|
|
72268
73081
|
return;
|
|
72269
73082
|
}
|
|
72270
|
-
let zone = undefined;
|
|
72271
|
-
const selectedZones = [];
|
|
72272
73083
|
const sheetId = this.getters.getActiveSheetId();
|
|
72273
|
-
const target = {
|
|
72274
|
-
sheetId,
|
|
72275
|
-
zones,
|
|
72276
|
-
};
|
|
72277
73084
|
const handlers = this.selectClipboardHandlers(copiedData);
|
|
72278
|
-
|
|
72279
|
-
const handlerData = copiedData[handlerName];
|
|
72280
|
-
if (!handlerData) {
|
|
72281
|
-
continue;
|
|
72282
|
-
}
|
|
72283
|
-
const currentTarget = handler.getPasteTarget(sheetId, zones, handlerData, options);
|
|
72284
|
-
if (currentTarget.figureId) {
|
|
72285
|
-
target.figureId = currentTarget.figureId;
|
|
72286
|
-
}
|
|
72287
|
-
for (const targetZone of currentTarget.zones) {
|
|
72288
|
-
selectedZones.push(targetZone);
|
|
72289
|
-
if (zone === undefined) {
|
|
72290
|
-
zone = targetZone;
|
|
72291
|
-
continue;
|
|
72292
|
-
}
|
|
72293
|
-
zone = union(zone, targetZone);
|
|
72294
|
-
}
|
|
72295
|
-
}
|
|
73085
|
+
const { target, zone, selectedZones } = getPasteTargetFromHandlers(sheetId, zones, copiedData, handlers, options);
|
|
72296
73086
|
if (zone !== undefined) {
|
|
72297
|
-
this.addMissingDimensions(
|
|
73087
|
+
this.addMissingDimensions(sheetId, zone.right - zone.left + 1, zone.bottom - zone.top + 1, zone.left, zone.top);
|
|
72298
73088
|
}
|
|
72299
|
-
handlers
|
|
72300
|
-
const handlerData = copiedData[handlerName];
|
|
72301
|
-
if (handlerData) {
|
|
72302
|
-
handler.paste(target, handlerData, options);
|
|
72303
|
-
}
|
|
72304
|
-
});
|
|
73089
|
+
applyClipboardHandlersPaste(handlers, copiedData, target, options);
|
|
72305
73090
|
if (!options?.selectTarget) {
|
|
72306
73091
|
return;
|
|
72307
73092
|
}
|
|
72308
|
-
|
|
72309
|
-
const col = selection.left;
|
|
72310
|
-
const row = selection.top;
|
|
72311
|
-
this.selection.getBackToDefault();
|
|
72312
|
-
this.selection.selectZone({ cell: { col, row }, zone: union(...selectedZones) }, { scrollIntoView: false });
|
|
73093
|
+
selectPastedZone(this.selection, zones, selectedZones);
|
|
72313
73094
|
}
|
|
72314
73095
|
/**
|
|
72315
73096
|
* Add columns and/or rows to ensure that col + width and row + height are still
|
|
@@ -75138,6 +75919,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75138
75919
|
return !!getters.getEvaluatedCell(position).link;
|
|
75139
75920
|
},
|
|
75140
75921
|
execute: (position, env, isMiddleClick) => openLink(env.model.getters.getEvaluatedCell(position).link, env, isMiddleClick),
|
|
75922
|
+
title: (position, getters) => {
|
|
75923
|
+
const link = getters.getEvaluatedCell(position).link;
|
|
75924
|
+
if (!link)
|
|
75925
|
+
return "";
|
|
75926
|
+
if (link.isExternal) {
|
|
75927
|
+
return _t("Go to url: %(url)s", { url: link.url });
|
|
75928
|
+
}
|
|
75929
|
+
else {
|
|
75930
|
+
return _t("Go to %(label)s", { label: link.label });
|
|
75931
|
+
}
|
|
75932
|
+
},
|
|
75141
75933
|
sequence: 5,
|
|
75142
75934
|
});
|
|
75143
75935
|
|
|
@@ -76849,12 +77641,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
76849
77641
|
if (!item) {
|
|
76850
77642
|
continue;
|
|
76851
77643
|
}
|
|
77644
|
+
const title = typeof item.title === "function" ? item.title(position, getters) : item.title;
|
|
76852
77645
|
const zone = getters.expandZone(sheetId, positionToZone(position));
|
|
76853
77646
|
cells.push({
|
|
76854
77647
|
coordinates: getters.getVisibleRect(zone),
|
|
76855
77648
|
position,
|
|
76856
77649
|
action: item.execute,
|
|
76857
|
-
title:
|
|
77650
|
+
title: title || "",
|
|
76858
77651
|
});
|
|
76859
77652
|
}
|
|
76860
77653
|
return cells;
|
|
@@ -77239,24 +78032,36 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
77239
78032
|
user-select: none;
|
|
77240
78033
|
color: ${TEXT_BODY};
|
|
77241
78034
|
|
|
78035
|
+
&.collapsed {
|
|
78036
|
+
padding: 8px;
|
|
78037
|
+
cursor: pointer;
|
|
78038
|
+
|
|
78039
|
+
.o-sidePanelTitle {
|
|
78040
|
+
writing-mode: vertical-rl;
|
|
78041
|
+
text-orientation: mixed;
|
|
78042
|
+
}
|
|
78043
|
+
}
|
|
78044
|
+
|
|
77242
78045
|
.o-sidePanelTitle {
|
|
77243
78046
|
line-height: 20px;
|
|
77244
78047
|
font-size: 16px;
|
|
77245
78048
|
}
|
|
77246
78049
|
|
|
77247
78050
|
.o-sidePanelHeader {
|
|
77248
|
-
padding: 8px
|
|
77249
|
-
display: flex;
|
|
77250
|
-
align-items: center;
|
|
77251
|
-
justify-content: space-between;
|
|
78051
|
+
padding: 8px;
|
|
77252
78052
|
border-bottom: 1px solid ${GRAY_300};
|
|
78053
|
+
}
|
|
77253
78054
|
|
|
77254
|
-
|
|
77255
|
-
|
|
77256
|
-
|
|
77257
|
-
|
|
77258
|
-
|
|
77259
|
-
}
|
|
78055
|
+
.o-sidePanelAction {
|
|
78056
|
+
padding: 5px 10px;
|
|
78057
|
+
cursor: pointer;
|
|
78058
|
+
|
|
78059
|
+
&.active {
|
|
78060
|
+
background-color: ${BUTTON_ACTIVE_BG};
|
|
78061
|
+
}
|
|
78062
|
+
|
|
78063
|
+
&:hover {
|
|
78064
|
+
background-color: ${BUTTON_HOVER_BG};
|
|
77260
78065
|
}
|
|
77261
78066
|
}
|
|
77262
78067
|
.o-sidePanelBody-container {
|
|
@@ -77333,43 +78138,114 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
77333
78138
|
`;
|
|
77334
78139
|
class SidePanel extends owl.Component {
|
|
77335
78140
|
static template = "o-spreadsheet-SidePanel";
|
|
78141
|
+
static props = {
|
|
78142
|
+
panelContent: Object,
|
|
78143
|
+
panelProps: Object,
|
|
78144
|
+
onCloseSidePanel: Function,
|
|
78145
|
+
onStartHandleDrag: Function,
|
|
78146
|
+
onResetPanelSize: Function,
|
|
78147
|
+
isPinned: { type: Boolean, optional: true },
|
|
78148
|
+
onTogglePinPanel: { type: Function, optional: true },
|
|
78149
|
+
onToggleCollapsePanel: { type: Function, optional: true },
|
|
78150
|
+
isCollapsed: { type: Boolean, optional: true },
|
|
78151
|
+
};
|
|
78152
|
+
spreadsheetRect = useSpreadsheetRect();
|
|
78153
|
+
getTitle() {
|
|
78154
|
+
const panel = this.props.panelContent;
|
|
78155
|
+
return typeof panel.title === "function"
|
|
78156
|
+
? panel.title(this.env, this.props.panelProps)
|
|
78157
|
+
: panel.title;
|
|
78158
|
+
}
|
|
78159
|
+
get pinInfoMessage() {
|
|
78160
|
+
return _t("Pin this panel to allow to open another side panel beside it.");
|
|
78161
|
+
}
|
|
78162
|
+
}
|
|
78163
|
+
|
|
78164
|
+
class SidePanels extends owl.Component {
|
|
78165
|
+
static template = "o-spreadsheet-SidePanels";
|
|
77336
78166
|
static props = {};
|
|
78167
|
+
static components = { SidePanel };
|
|
77337
78168
|
sidePanelStore;
|
|
77338
78169
|
spreadsheetRect = useSpreadsheetRect();
|
|
77339
78170
|
setup() {
|
|
77340
78171
|
this.sidePanelStore = useStore(SidePanelStore);
|
|
77341
|
-
owl.useEffect((
|
|
77342
|
-
if (!
|
|
78172
|
+
owl.useEffect(() => {
|
|
78173
|
+
if (this.sidePanelStore.mainPanel && !this.sidePanelStore.isMainPanelOpen) {
|
|
78174
|
+
this.sidePanelStore.closeMainPanel();
|
|
78175
|
+
}
|
|
78176
|
+
if (this.sidePanelStore.secondaryPanel && !this.sidePanelStore.isSecondaryPanelOpen) {
|
|
77343
78177
|
this.sidePanelStore.close();
|
|
77344
78178
|
}
|
|
77345
|
-
}, () => [this.sidePanelStore.
|
|
77346
|
-
}
|
|
77347
|
-
get panel() {
|
|
77348
|
-
return sidePanelRegistry.get(this.sidePanelStore.componentTag);
|
|
77349
|
-
}
|
|
77350
|
-
close() {
|
|
77351
|
-
this.sidePanelStore.close();
|
|
78179
|
+
}, () => [this.sidePanelStore.isMainPanelOpen, this.sidePanelStore.isSecondaryPanelOpen]);
|
|
77352
78180
|
}
|
|
77353
|
-
|
|
77354
|
-
const panel = this.panel;
|
|
77355
|
-
return typeof panel.title === "function"
|
|
77356
|
-
? panel.title(this.env, this.sidePanelStore.panelProps)
|
|
77357
|
-
: panel.title;
|
|
77358
|
-
}
|
|
77359
|
-
startHandleDrag(ev) {
|
|
78181
|
+
startHandleDrag(panel, ev) {
|
|
77360
78182
|
const startingCursor = document.body.style.cursor;
|
|
77361
|
-
const
|
|
78183
|
+
const panelInfo = panel === "mainPanel" ? this.sidePanelStore.mainPanel : this.sidePanelStore.secondaryPanel;
|
|
78184
|
+
if (!panelInfo) {
|
|
78185
|
+
return;
|
|
78186
|
+
}
|
|
78187
|
+
const startSize = panelInfo.size;
|
|
77362
78188
|
const startPosition = ev.clientX;
|
|
77363
78189
|
const onMouseMove = (ev) => {
|
|
77364
78190
|
document.body.style.cursor = "col-resize";
|
|
77365
78191
|
const newSize = startSize + startPosition - ev.clientX;
|
|
77366
|
-
this.sidePanelStore.changePanelSize(
|
|
78192
|
+
this.sidePanelStore.changePanelSize(panel, newSize);
|
|
77367
78193
|
};
|
|
77368
78194
|
const cleanUp = () => {
|
|
77369
78195
|
document.body.style.cursor = startingCursor;
|
|
77370
78196
|
};
|
|
77371
78197
|
startDnd(onMouseMove, cleanUp);
|
|
77372
78198
|
}
|
|
78199
|
+
get mainPanelProps() {
|
|
78200
|
+
const panelProps = this.sidePanelStore.mainPanelProps;
|
|
78201
|
+
if (!this.sidePanelStore.mainPanel || !panelProps) {
|
|
78202
|
+
return undefined;
|
|
78203
|
+
}
|
|
78204
|
+
return {
|
|
78205
|
+
panelContent: sidePanelRegistry.get(this.sidePanelStore.mainPanel.componentTag),
|
|
78206
|
+
panelProps,
|
|
78207
|
+
onCloseSidePanel: () => this.sidePanelStore.closeMainPanel(),
|
|
78208
|
+
onTogglePinPanel: () => this.sidePanelStore.togglePinPanel(),
|
|
78209
|
+
onStartHandleDrag: (ev) => this.startHandleDrag("mainPanel", ev),
|
|
78210
|
+
onResetPanelSize: () => this.sidePanelStore.resetPanelSize("mainPanel"),
|
|
78211
|
+
isPinned: this.sidePanelStore.mainPanel?.isPinned,
|
|
78212
|
+
onToggleCollapsePanel: () => this.sidePanelStore.toggleCollapsePanel("mainPanel"),
|
|
78213
|
+
isCollapsed: this.sidePanelStore.mainPanel?.isCollapsed,
|
|
78214
|
+
};
|
|
78215
|
+
}
|
|
78216
|
+
get secondaryPanelProps() {
|
|
78217
|
+
const panelProps = this.sidePanelStore.secondaryPanelProps;
|
|
78218
|
+
if (!this.sidePanelStore.secondaryPanel || !panelProps) {
|
|
78219
|
+
return undefined;
|
|
78220
|
+
}
|
|
78221
|
+
return {
|
|
78222
|
+
panelContent: sidePanelRegistry.get(this.sidePanelStore.secondaryPanel.componentTag),
|
|
78223
|
+
panelProps,
|
|
78224
|
+
onCloseSidePanel: () => this.sidePanelStore.close(),
|
|
78225
|
+
onStartHandleDrag: (ev) => this.startHandleDrag("secondaryPanel", ev),
|
|
78226
|
+
onResetPanelSize: () => this.sidePanelStore.resetPanelSize("secondaryPanel"),
|
|
78227
|
+
onToggleCollapsePanel: () => this.sidePanelStore.toggleCollapsePanel("secondaryPanel"),
|
|
78228
|
+
isCollapsed: this.sidePanelStore.secondaryPanel?.isCollapsed,
|
|
78229
|
+
};
|
|
78230
|
+
}
|
|
78231
|
+
get panelList() {
|
|
78232
|
+
return [
|
|
78233
|
+
{
|
|
78234
|
+
key: this.sidePanelStore.secondaryPanelKey,
|
|
78235
|
+
props: this.secondaryPanelProps,
|
|
78236
|
+
style: this.sidePanelStore.secondaryPanel
|
|
78237
|
+
? cssPropertiesToCss({ width: `${this.sidePanelStore.secondaryPanel.size}px` })
|
|
78238
|
+
: "",
|
|
78239
|
+
},
|
|
78240
|
+
{
|
|
78241
|
+
key: this.sidePanelStore.mainPanelKey,
|
|
78242
|
+
props: this.mainPanelProps,
|
|
78243
|
+
style: this.sidePanelStore.mainPanel
|
|
78244
|
+
? cssPropertiesToCss({ width: `${this.sidePanelStore.mainPanel.size}px` })
|
|
78245
|
+
: "",
|
|
78246
|
+
},
|
|
78247
|
+
].filter((panel) => panel.key && panel.props);
|
|
78248
|
+
}
|
|
77373
78249
|
}
|
|
77374
78250
|
|
|
77375
78251
|
class RibbonMenu extends owl.Component {
|
|
@@ -78931,7 +79807,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
78931
79807
|
Grid,
|
|
78932
79808
|
BottomBar,
|
|
78933
79809
|
SmallBottomBar,
|
|
78934
|
-
|
|
79810
|
+
SidePanels,
|
|
78935
79811
|
SpreadsheetDashboard,
|
|
78936
79812
|
HeaderGroupContainer,
|
|
78937
79813
|
FullScreenChart,
|
|
@@ -78954,7 +79830,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
78954
79830
|
else {
|
|
78955
79831
|
properties["grid-template-rows"] = `min-content auto min-content`;
|
|
78956
79832
|
}
|
|
78957
|
-
const columnWidth = this.sidePanel.
|
|
79833
|
+
const columnWidth = this.sidePanel.mainPanel
|
|
79834
|
+
? `${this.sidePanel.totalPanelSize || DEFAULT_SIDE_PANEL_SIZE}px`
|
|
79835
|
+
: "auto";
|
|
78958
79836
|
properties["grid-template-columns"] = `auto ${columnWidth}`;
|
|
78959
79837
|
return cssPropertiesToCss(properties);
|
|
78960
79838
|
}
|
|
@@ -79038,7 +79916,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
79038
79916
|
this.checkViewportSize();
|
|
79039
79917
|
});
|
|
79040
79918
|
const resizeObserver = new ResizeObserver(() => {
|
|
79041
|
-
this.sidePanel.
|
|
79919
|
+
this.sidePanel.changeSpreadsheetWidth(this.spreadsheetRect.width);
|
|
79042
79920
|
});
|
|
79043
79921
|
}
|
|
79044
79922
|
bindModelEvents() {
|
|
@@ -80153,26 +81031,28 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
80153
81031
|
bottom: Math.min(this.getters.getNumberRows(sheetId) - 1, bottom),
|
|
80154
81032
|
};
|
|
80155
81033
|
};
|
|
80156
|
-
const {
|
|
81034
|
+
const { cell: refCell, zone: refZone } = this.getReferenceAnchor();
|
|
81035
|
+
const { col: refCol, row: refRow } = refCell;
|
|
80157
81036
|
// check if we can shrink selection
|
|
80158
81037
|
let n = 0;
|
|
80159
81038
|
while (result !== null) {
|
|
80160
81039
|
n++;
|
|
80161
81040
|
if (deltaCol < 0) {
|
|
80162
81041
|
const newRight = this.getNextAvailableCol(deltaCol, right - (n - 1), refRow);
|
|
80163
|
-
result =
|
|
81042
|
+
result = refZone.right <= right - n ? expand({ top, left, bottom, right: newRight }) : null;
|
|
80164
81043
|
}
|
|
80165
81044
|
if (deltaCol > 0) {
|
|
80166
81045
|
const newLeft = this.getNextAvailableCol(deltaCol, left + (n - 1), refRow);
|
|
80167
|
-
result = left + n <=
|
|
81046
|
+
result = left + n <= refZone.left ? expand({ top, left: newLeft, bottom, right }) : null;
|
|
80168
81047
|
}
|
|
80169
81048
|
if (deltaRow < 0) {
|
|
80170
81049
|
const newBottom = this.getNextAvailableRow(deltaRow, refCol, bottom - (n - 1));
|
|
80171
|
-
result =
|
|
81050
|
+
result =
|
|
81051
|
+
refZone.bottom <= bottom - n ? expand({ top, left, bottom: newBottom, right }) : null;
|
|
80172
81052
|
}
|
|
80173
81053
|
if (deltaRow > 0) {
|
|
80174
81054
|
const newTop = this.getNextAvailableRow(deltaRow, refCol, top + (n - 1));
|
|
80175
|
-
result = top + n <=
|
|
81055
|
+
result = top + n <= refZone.top ? expand({ top: newTop, left, bottom, right }) : null;
|
|
80176
81056
|
}
|
|
80177
81057
|
result = result ? reorderZone(result) : result;
|
|
80178
81058
|
if (result && !isEqual(result, anchor.zone)) {
|
|
@@ -80402,18 +81282,26 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
80402
81282
|
* If the anchor is hidden, browses from left to right and top to bottom to
|
|
80403
81283
|
* find a visible cell.
|
|
80404
81284
|
*/
|
|
80405
|
-
|
|
81285
|
+
getReferenceAnchor() {
|
|
80406
81286
|
const sheetId = this.getters.getActiveSheetId();
|
|
80407
81287
|
const anchor = this.anchor;
|
|
80408
81288
|
const { left, right, top, bottom } = anchor.zone;
|
|
80409
81289
|
const { col: anchorCol, row: anchorRow } = anchor.cell;
|
|
81290
|
+
const col = this.getters.isColHidden(sheetId, anchorCol)
|
|
81291
|
+
? this.getters.findVisibleHeader(sheetId, "COL", left, right) || anchorCol
|
|
81292
|
+
: anchorCol;
|
|
81293
|
+
const row = this.getters.isRowHidden(sheetId, anchorRow)
|
|
81294
|
+
? this.getters.findVisibleHeader(sheetId, "ROW", top, bottom) || anchorRow
|
|
81295
|
+
: anchorRow;
|
|
81296
|
+
const zone = this.getters.expandZone(sheetId, {
|
|
81297
|
+
left: col,
|
|
81298
|
+
right: col,
|
|
81299
|
+
top: row,
|
|
81300
|
+
bottom: row,
|
|
81301
|
+
});
|
|
80410
81302
|
return {
|
|
80411
|
-
|
|
80412
|
-
|
|
80413
|
-
: anchorCol,
|
|
80414
|
-
row: this.getters.isRowHidden(sheetId, anchorRow)
|
|
80415
|
-
? this.getters.findVisibleHeader(sheetId, "ROW", top, bottom) || anchorRow
|
|
80416
|
-
: anchorRow,
|
|
81303
|
+
cell: { col, row },
|
|
81304
|
+
zone,
|
|
80417
81305
|
};
|
|
80418
81306
|
}
|
|
80419
81307
|
deltaToTarget(position, direction, step) {
|
|
@@ -83635,9 +84523,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
83635
84523
|
exports.tokenize = tokenize;
|
|
83636
84524
|
|
|
83637
84525
|
|
|
83638
|
-
__info__.version = "18.4.
|
|
83639
|
-
__info__.date = "2025-06-
|
|
83640
|
-
__info__.hash = "
|
|
84526
|
+
__info__.version = "18.4.1";
|
|
84527
|
+
__info__.date = "2025-06-27T09:13:01.303Z";
|
|
84528
|
+
__info__.hash = "5cecc0e";
|
|
83641
84529
|
|
|
83642
84530
|
|
|
83643
84531
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|