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