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