Skip to content

Commit 152e2cb

Browse files
committed
[IMP] Cells: set explicit style on hyperlink-like content
Currently, we apply a custom style to the cells that contain a content similar to a hyper/markdown link during the rendering process. This means that this style disappears once we export the spreadsheet to other formats (.xlsx for instance ). Furthermore, the detection depends on the elements added to `urlRegistry`. In some cases (specifically when loading a spreadsheet in a public page in Odoo) we might populate this registry differently, which leads to a difference of behaviour between renderers of the same raw content. Since the style was computed during the rendering process, it means that you could not just "get rid" of that style, you had to define a dedicated style to override it, so 'clear format' would never work. This revision changes our strategy and tries to explicitely apply a specific style when adding a content detected as a hyperlink/markdownling. This way, we ensure that the style is hardcoded in the data and will be consistent when we export it in .xslx files or if we show it on a public page in Odoo. Task: 5410289
1 parent 6fe9f42 commit 152e2cb

File tree

12 files changed

+133
-21
lines changed

12 files changed

+133
-21
lines changed

demo/data.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ export const demoData = {
116116
F2: 5,
117117
F3: 6,
118118
F4: 7,
119+
A21: 30,
119120
},
120121
formats: {
121122
C22: 1,
@@ -3526,6 +3527,11 @@ export const demoData = {
35263527
11: {
35273528
bold: true,
35283529
},
3530+
30: {
3531+
bold: true,
3532+
fontSize: 18,
3533+
fillColor: "#FFFF00",
3534+
},
35293535
},
35303536
formats: {
35313537
1: "0.00%",

packages/o-spreadsheet-engine/src/helpers/data_normalization.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ const globalIdCounter = new WeakMap<ItemsDic<any>, number>();
1515
export function getItemId<T>(item: T, itemsDic: ItemsDic<T>) {
1616
if (!globalReverseLookup.has(itemsDic)) {
1717
globalReverseLookup.set(itemsDic, new Map());
18-
globalIdCounter.set(itemsDic, 0);
18+
const x = Math.max(...Object.keys(itemsDic).map((k) => Number(k)), 0);
19+
globalIdCounter.set(itemsDic, x);
1920
}
2021
const reverseLookup = globalReverseLookup.get(itemsDic)!;
2122
const canonical = getCanonicalRepresentation(item);

packages/o-spreadsheet-engine/src/helpers/misc.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ export function parseSheetUrl(sheetLink: string) {
236236
throw new Error(`${sheetLink} is not a valid sheet link`);
237237
}
238238

239+
export function hasHyperlinkContent(content: string): boolean {
240+
return isMarkdownLink(content) || isWebLink(content) || content.startsWith("=HYPERLINK(");
241+
}
242+
239243
/**
240244
* This helper function can be used as a type guard when filtering arrays.
241245
* const foo: number[] = [1, 2, undefined, 4].filter(isDefined)

packages/o-spreadsheet-engine/src/migrations/data.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ export function repairInitialMessages(
218218
initialMessages = fixChartDefinitions(data, initialMessages);
219219
initialMessages = fixFigureOffset(data, initialMessages);
220220
initialMessages = fixTranslatedDuplicateSheetName(data, initialMessages);
221+
initialMessages = fixHyperlinkCellUpdate(data, initialMessages);
221222
return initialMessages;
222223
}
223224

@@ -408,6 +409,13 @@ function fixTranslatedDuplicateSheetName(
408409
return initialMessages;
409410
}
410411

412+
function fixHyperlinkCellUpdate(
413+
data: Partial<WorkbookData>,
414+
initialMessages: StateUpdateMessage[]
415+
) {
416+
return initialMessages;
417+
}
418+
411419
// -----------------------------------------------------------------------------
412420
// Helpers
413421
// -----------------------------------------------------------------------------

packages/o-spreadsheet-engine/src/migrations/migration_steps.ts

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { BACKGROUND_CHART_COLOR, FORMULA_REF_IDENTIFIER } from "../constants";
1+
import { BACKGROUND_CHART_COLOR, FORMULA_REF_IDENTIFIER, LINK_COLOR } from "../constants";
22
import { toXC } from "../helpers/coordinates";
33
import { getItemId } from "../helpers/data_normalization";
4-
import { getUniqueText, sanitizeSheetName } from "../helpers/misc";
4+
import { getUniqueText, isMarkdownLink, isWebLink, sanitizeSheetName } from "../helpers/misc";
55
import { getMaxObjectId } from "../helpers/pivot/pivot_helpers";
6+
import { recomputeZones } from "../helpers/recompute_zones";
67
import { DEFAULT_TABLE_CONFIG } from "../helpers/table_presets";
7-
import { overlap, toZone, zoneToXc } from "../helpers/zones";
8+
import { isZoneInside, overlap, toZone, zoneToXc } from "../helpers/zones";
89
import { Registry } from "../registry";
910
import { CustomizedDataSet, schemeToColorScale } from "../types/chart";
1011
import { Format } from "../types/format";
@@ -576,6 +577,11 @@ migrationStepRegistry
576577
}
577578
return data;
578579
},
580+
})
581+
.add("19.2.0", {
582+
migrate(data: WorkbookData): any {
583+
return addHyperlinkStyle(data);
584+
},
579585
});
580586

581587
function fixOverlappingFilters(data: any): any {
@@ -600,3 +606,56 @@ function fixOverlappingFilters(data: any): any {
600606
}
601607
return data;
602608
}
609+
610+
function addHyperlinkStyle(data: WorkbookData): WorkbookData {
611+
for (const sheet of data.sheets || []) {
612+
for (const xc in sheet.cells || {}) {
613+
const content = sheet.cells[xc];
614+
if (content && (isMarkdownLink(content) || isWebLink(content))) {
615+
// debugger;
616+
// find the XC in the styles
617+
const styleXc = Object.keys(sheet.styles).find((styleXC) =>
618+
isZoneInside(toZone(xc), toZone(styleXC))
619+
);
620+
if (styleXc) {
621+
// vérifier qu'il y a textcolor; si c'est le cas, on ne fait rien
622+
if (data.styles[sheet.styles[styleXc]].textColor) {
623+
continue;
624+
}
625+
// sinon, on split le truc existant et on ajourte la couleur juste pour nous.
626+
627+
const existingStyleId = sheet.styles[styleXc];
628+
const existingStyle = data.styles[existingStyleId];
629+
630+
const zones = recomputeZones([toZone(styleXc)], [toZone(xc)]);
631+
632+
delete sheet.styles[styleXc];
633+
634+
zones.forEach((zone) => {
635+
const zoneXc = zoneToXc(zone);
636+
sheet.styles[zoneXc] = existingStyleId;
637+
});
638+
639+
sheet.styles[xc] = getItemId({ ...existingStyle, textColor: LINK_COLOR }, data.styles);
640+
641+
/**
642+
* Stylexc > tozone
643+
* zones << recomputezone without xc
644+
*
645+
* delete sheet styleXc
646+
* add all zones with the existing style
647+
* add xc with the existing style + textcolor as a new style
648+
*
649+
*
650+
*/
651+
// utiliser getItemId
652+
}
653+
// Si on n'a pas de style existant, ou pas de textcolor, on ajoute la couleur et un style a part
654+
else {
655+
sheet.styles[xc] = getItemId({ textColor: LINK_COLOR }, data.styles);
656+
}
657+
}
658+
}
659+
}
660+
return data;
661+
}

packages/o-spreadsheet-engine/src/plugins/ui_feature/cell_computed_style.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { LINK_COLOR } from "../../constants";
21
import { PositionMap } from "../../helpers/cells/position_map";
32
import { isObjectEmptyRecursive, removeFalsyAttributes } from "../../helpers/misc";
43
import { positionToZone } from "../../helpers/zones";
@@ -107,10 +106,6 @@ export class CellComputedStylePlugin extends UIPlugin {
107106
...removeFalsyAttributes(styles.get(position)),
108107
...removeFalsyAttributes(this.getters.getCellConditionalFormatStyle(position)),
109108
};
110-
const evaluatedCell = this.getters.getEvaluatedCell(position);
111-
if (evaluatedCell.link && !computedStyle.textColor) {
112-
computedStyle.textColor = LINK_COLOR;
113-
}
114109
this.styles.set(position, computedStyle);
115110
}
116111
}

src/components/composer/composer/cell_composer_store.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { parseTokens } from "@odoo/o-spreadsheet-engine";
1+
import { hasHyperlinkContent, parseTokens, Style } from "@odoo/o-spreadsheet-engine";
2+
import { LINK_COLOR } from "@odoo/o-spreadsheet-engine/constants";
23
import { prettify } from "@odoo/o-spreadsheet-engine/formulas/formula_formatter";
34
import {
45
isMultipleElementMatrix,
@@ -28,9 +29,9 @@ import {
2829
Direction,
2930
Format,
3031
FormulaCell,
32+
isMatrix,
3133
Locale,
3234
RemoveColumnsRowsCommand,
33-
isMatrix,
3435
} from "../../../types";
3536
import { AbstractComposerStore, ComposerSelection } from "./abstract_composer_store";
3637

@@ -189,10 +190,19 @@ export class CellComposerStore extends AbstractComposerStore {
189190
if (cell.link && !isFormula(content)) {
190191
content = markdownLink(content, cell.link.url);
191192
}
193+
/** si pas de cell core || cell core a un style */
194+
let style: Style | undefined;
195+
// if ()
196+
const cellStyle = this.getters.getCellStyle(this.currentEditedCell);
197+
if ((!cellStyle || !cellStyle.textColor) && hasHyperlinkContent(content)) {
198+
style = { ...cellStyle, textColor: LINK_COLOR };
199+
}
200+
192201
this.addHeadersForSpreadingFormula(content);
193202
this.model.dispatch("UPDATE_CELL", {
194203
...this.currentEditedCell,
195204
content,
205+
style,
196206
});
197207
} else {
198208
this.model.dispatch("UPDATE_CELL", {

src/components/link/link_editor/link_editor.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { LINK_COLOR } from "@odoo/o-spreadsheet-engine/constants";
12
import { detectLink, urlRepresentation } from "@odoo/o-spreadsheet-engine/helpers/links";
23
import { canonicalizeNumberContent } from "@odoo/o-spreadsheet-engine/helpers/locale";
34
import { SpreadsheetChildEnv } from "@odoo/o-spreadsheet-engine/types/spreadsheet_env";
@@ -86,16 +87,20 @@ export class LinkEditor extends Component<LinkEditorProps, SpreadsheetChildEnv>
8687
}
8788

8889
save() {
90+
const sheetId = this.env.model.getters.getActiveSheetId();
8991
const { col, row } = this.props.cellPosition;
9092
const locale = this.env.model.getters.getLocale();
9193
const label = this.link.label
9294
? canonicalizeNumberContent(this.link.label, locale)
9395
: this.link.url;
96+
// TODORAR add this feature to UPDATE_CELL in the composr as well ?
97+
const style = this.env.model.getters.getCellStyle({ sheetId, col, row });
9498
this.env.model.dispatch("UPDATE_CELL", {
95-
col: col,
96-
row: row,
97-
sheetId: this.env.model.getters.getActiveSheetId(),
99+
col,
100+
row,
101+
sheetId,
98102
content: markdownLink(label, this.link.url),
103+
style: { ...style, textColor: LINK_COLOR },
99104
});
100105
this.props.onClosed?.();
101106
}

tests/cells/cell_plugin.test.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { LINK_COLOR } from "@odoo/o-spreadsheet-engine/constants";
21
import { urlRepresentation } from "@odoo/o-spreadsheet-engine/helpers/links";
32
import { corePluginRegistry } from "@odoo/o-spreadsheet-engine/plugins";
43
import { CoreCommand, CorePlugin, Model } from "../../src";
@@ -31,7 +30,6 @@ import {
3130
getCellStyle,
3231
getCellText,
3332
getEvaluatedCell,
34-
getStyle,
3533
} from "../test_helpers/getters_helpers";
3634
import { addTestPlugin, getGrid, setGrid, target } from "../test_helpers/helpers";
3735

@@ -266,7 +264,6 @@ describe("link cell", () => {
266264
expect(cell.link?.url).toBe(url);
267265
expect(urlRepresentation(cell.link!, model.getters)).toBe(url);
268266
expect(getCell(model, "A1")?.content).toBe(`[my label](${url})`);
269-
expect(getStyle(model, "A1")).toEqual({ textColor: LINK_COLOR });
270267
expect(getCellText(model, "A1")).toBe("my label");
271268
}
272269
);
@@ -281,7 +278,6 @@ describe("link cell", () => {
281278
expect(cell.link?.url).toBe(url);
282279
expect(urlRepresentation(cell.link!, model.getters)).toBe(url);
283280
expect(getCell(model, "B1")?.content).toBe(`=HYPERLINK("${url}", "Odoo")`);
284-
expect(getStyle(model, "B1")).toEqual({ textColor: LINK_COLOR });
285281
expect(getCellText(model, "B1")).toBe(`=HYPERLINK("${url}", "Odoo")`);
286282
}
287283
);

tests/clipboard/clipboard_plugin.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DEFAULT_BORDER_DESC, LINK_COLOR } from "@odoo/o-spreadsheet-engine/constants";
1+
import { DEFAULT_BORDER_DESC } from "@odoo/o-spreadsheet-engine/constants";
22
import {
33
getClipboardDataPositions,
44
parseOSClipboardContent,
@@ -3026,7 +3026,6 @@ describe("cross spreadsheet copy/paste", () => {
30263026
expect(cell.link?.url).toBe(url);
30273027
expect(urlRepresentation(cell.link!, modelB.getters)).toBe(url);
30283028
expect(getCell(modelB, "D1")?.content).toBe("[Odoo Website](https://www.odoo.com)");
3029-
expect(getStyle(modelB, "D1")).toEqual({ textColor: LINK_COLOR });
30303029
expect(getCellText(modelB, "D1")).toBe("Odoo Website");
30313030
});
30323031

0 commit comments

Comments
 (0)