Skip to content

Commit

Permalink
[REF] figure: unify chart and image menus
Browse files Browse the repository at this point in the history
Before this commit, the chart and image menus were handled separately in
`figure_chart.ts` and `figure_image.ts`. This led to a lot of duplicated code
since they both do 80% the same thing.

Now the figure menu is handled in `figure.ts`, and a `menuRegistryBuilder`
was added to `figureRegistry`.

Odoo task 3199007

closes #2091

Signed-off-by: Lucas Lefèvre (lul) <[email protected]>
  • Loading branch information
hokolomopo authored and LucasLefevre committed Mar 9, 2023
1 parent cd919f0 commit c8dd315
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 282 deletions.
44 changes: 39 additions & 5 deletions src/components/figures/figure/figure.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { Component, useEffect, useRef } from "@odoo/owl";
import { Component, useEffect, useRef, useState } from "@odoo/owl";
import {
ComponentsImportance,
FIGURE_BORDER_COLOR,
MENU_WIDTH,
SELECTION_BORDER_COLOR,
} from "../../../constants";
import { figureRegistry } from "../../../registries/index";
import {
CSSProperties,
DOMCoordinates,
Figure,
Pixel,
ResizeDirection,
SpreadsheetChildEnv,
UID,
} from "../../../types/index";
import { css, cssPropertiesToCss } from "../../helpers/css";
import { useAbsoluteBoundingRect } from "../../helpers/position_hook";
import { Menu, MenuState } from "../../menu/menu";

type ResizeAnchor =
| "top left"
Expand Down Expand Up @@ -90,9 +94,8 @@ css/*SCSS*/ `
.o-figure-menu {
right: 0px;
top: 0px;
display: none;
position: absolute;
padding: 5px;
}
.o-figure-menu-item {
Expand All @@ -118,15 +121,20 @@ interface Props {

export class FigureComponent extends Component<Props, SpreadsheetChildEnv> {
static template = "o-spreadsheet-FigureComponent";
static components = {};
static components = { Menu };
static defaultProps = {
onFigureDeleted: () => {},
onMouseDown: () => {},
onClickAnchor: () => {},
};

private borderWidth!: number;
private menuState: MenuState = useState({ isOpen: false, position: null, menuItems: [] });

private figureRef = useRef("figure");
private menuButtonRef = useRef("menuButton");
private menuButtonRect = useAbsoluteBoundingRect(this.menuButtonRef);

private borderWidth!: number;

get isSelected(): boolean {
return this.env.model.getters.getSelectedFigureId() === this.props.figure.id;
Expand Down Expand Up @@ -243,6 +251,32 @@ export class FigureComponent extends Component<Props, SpreadsheetChildEnv> {
break;
}
}

onContextMenu(ev: MouseEvent) {
if (this.env.isDashboard()) return;
const position = {
x: ev.clientX,
y: ev.clientY,
};
this.openContextMenu(position);
}

showMenu() {
const { x, y, width } = this.menuButtonRect;
const menuPosition = {
x: x >= MENU_WIDTH ? x - MENU_WIDTH : x + width,
y: y,
};
this.openContextMenu(menuPosition);
}

private openContextMenu(position: DOMCoordinates) {
this.menuState.isOpen = true;
this.menuState.position = position;
this.menuState.menuItems = figureRegistry
.get(this.props.figure.tag)
.menuBuilder(this.props.figure.id, this.props.onFigureDeleted, this.env);
}
}

FigureComponent.props = {
Expand Down
16 changes: 16 additions & 0 deletions src/components/figures/figure/figure.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<div
class="o-figure w-100 h-100"
t-on-mousedown.stop="(ev) => this.onMouseDown(ev)"
t-on-contextmenu.prevent.stop="onContextMenu"
t-ref="figure"
t-att-style="props.style"
tabindex="0"
Expand All @@ -15,6 +16,21 @@
onFigureDeleted="props.onFigureDeleted"
figure="props.figure"
/>
<div class="o-figure-menu position-absolute m-2" t-if="!env.isDashboard()">
<div
class="o-figure-menu-item"
t-on-click="showMenu"
t-ref="menuButton"
t-on-contextmenu.prevent.stop="showMenu">
<t t-call="o-spreadsheet-Icon.LIST"/>
</div>
<Menu
t-if="menuState.isOpen"
position="menuState.position"
menuItems="menuState.menuItems"
onClose="() => this.menuState.isOpen=false"
/>
</div>
</div>
<div class="o-figure-border w-100 h-100 position-absolute pe-none" t-att-style="borderStyle"/>
<t t-if="isSelected">
Expand Down
83 changes: 3 additions & 80 deletions src/components/figures/figure_chart/figure_chart.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { Component, useRef, useState } from "@odoo/owl";
import { MENU_WIDTH } from "../../../constants";
import { Component } from "@odoo/owl";
import { chartComponentRegistry } from "../../../registries/chart_types";
import { MenuItemRegistry } from "../../../registries/menu_items_registry";
import { _lt } from "../../../translation";
import { ChartType, DOMCoordinates, Figure, SpreadsheetChildEnv } from "../../../types";
import { ChartType, Figure, SpreadsheetChildEnv } from "../../../types";
import { css } from "../../helpers/css";
import { useAbsoluteBoundingRect } from "../../helpers/position_hook";
import { Menu, MenuState } from "../../menu/menu";

// -----------------------------------------------------------------------------
// STYLE
Expand All @@ -28,84 +23,12 @@ interface Props {

export class ChartFigure extends Component<Props, SpreadsheetChildEnv> {
static template = "o-spreadsheet-ChartFigure";
static components = { Menu };
private menuState: MenuState = useState({ isOpen: false, position: null, menuItems: [] });

private chartContainerRef = useRef("chartContainer");
private menuButtonRef = useRef("menuButton");
private menuButtonRect = useAbsoluteBoundingRect(this.menuButtonRef);
private position: DOMCoordinates = useAbsoluteBoundingRect(this.chartContainerRef);

private getMenuItemRegistry(): MenuItemRegistry {
const registry = new MenuItemRegistry();
registry.add("edit", {
name: _lt("Edit"),
sequence: 1,
action: () => {
this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figure.id });
this.env.openSidePanel("ChartPanel");
},
});
registry.add("copy", {
name: _lt("Copy"),
sequence: 2,
action: async () => {
this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figure.id });
this.env.model.dispatch("COPY");
await this.env.clipboard.write(this.env.model.getters.getClipboardContent());
},
});
registry.add("cut", {
name: _lt("Cut"),
sequence: 3,
action: async () => {
this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figure.id });
this.env.model.dispatch("CUT");
await this.env.clipboard.write(this.env.model.getters.getClipboardContent());
},
});
registry.add("delete", {
name: _lt("Delete"),
sequence: 10,
action: () => {
this.env.model.dispatch("DELETE_FIGURE", {
sheetId: this.env.model.getters.getActiveSheetId(),
id: this.props.figure.id,
});
this.props.onFigureDeleted();
},
});
return registry;
}
static components = {};

get chartType(): ChartType {
return this.env.model.getters.getChartType(this.props.figure.id);
}

onContextMenu(ev: MouseEvent) {
const position = {
x: this.position.x + ev.offsetX,
y: this.position.y + ev.offsetY,
};
this.openContextMenu(position);
}

showMenu() {
const { x, y, width } = this.menuButtonRect;
const menuPosition = {
x: x >= MENU_WIDTH ? x - MENU_WIDTH : x + width,
y: y,
};
this.openContextMenu(menuPosition);
}

private openContextMenu(position: DOMCoordinates) {
const registry = this.getMenuItemRegistry();
this.menuState.isOpen = true;
this.menuState.menuItems = registry.getMenuItems();
this.menuState.position = position;
}

get chartComponent(): new (...args: any) => Component {
const type = this.chartType;
const component = chartComponentRegistry.get(type);
Expand Down
21 changes: 1 addition & 20 deletions src/components/figures/figure_chart/figure_chart.xml
Original file line number Diff line number Diff line change
@@ -1,30 +1,11 @@
<templates>
<t t-name="o-spreadsheet-ChartFigure" owl="1">
<div
class="o-chart-container w-100 h-100"
t-ref="chartContainer"
t-on-contextmenu.prevent.stop="(ev) => !env.isDashboard() and this.onContextMenu(ev)">
<div class="o-figure-menu" t-if="!env.isDashboard()">
<div
class="o-figure-menu-item"
t-on-click="showMenu"
t-ref="menuButton"
t-on-contextmenu.prevent.stop="showMenu">
<t t-call="o-spreadsheet-Icon.LIST"/>
</div>
</div>
<div class="o-chart-container w-100 h-100">
<t
t-component="chartComponent"
figure="this.props.figure"
t-key="this.props.figure.id + '-' + chartType"
/>

<Menu
t-if="menuState.isOpen"
position="menuState.position"
menuItems="menuState.menuItems"
onClose="() => this.menuState.isOpen=false"
/>
</div>
</t>
</templates>
91 changes: 3 additions & 88 deletions src/components/figures/figure_image/figure_image.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import { Component, useRef, useState } from "@odoo/owl";
import { MENU_WIDTH } from "../../../constants";
import { getMaxFigureSize } from "../../../helpers/figures/figure/figure";
import { createMenu } from "../../../registries/menu_items_registry";
import { _lt } from "../../../translation";
import { DOMCoordinates, Figure, SpreadsheetChildEnv, UID } from "../../../types";
import { useAbsoluteBoundingRect } from "../../helpers/position_hook";
import { Menu, MenuState } from "../../menu/menu";
import { Component } from "@odoo/owl";
import { Figure, SpreadsheetChildEnv, UID } from "../../../types";

interface Props {
figure: Figure;
Expand All @@ -14,86 +8,7 @@ interface Props {

export class ImageFigure extends Component<Props, SpreadsheetChildEnv> {
static template = "o-spreadsheet-ImageFigure";
static components = { Menu };
private menuState: Pick<MenuState, "isOpen" | "position"> = useState({
isOpen: false,
position: null,
});

private imageContainerRef = useRef("o-image");
private menuButtonRef = useRef("menuButton");
private menuButtonRect = useAbsoluteBoundingRect(this.menuButtonRef);
private position: DOMCoordinates = useAbsoluteBoundingRect(this.imageContainerRef);

readonly menuItems = createMenu([
{
id: "copy",
name: _lt("Copy"),
description: "Ctrl+C",
action: async () => {
this.env.model.dispatch("SELECT_FIGURE", { id: this.figureId });
this.env.model.dispatch("COPY");
await this.env.clipboard.write(this.env.model.getters.getClipboardContent());
},
},
{
id: "cut",
name: _lt("Cut"),
description: "Ctrl+X",
action: async () => {
this.env.model.dispatch("SELECT_FIGURE", { id: this.figureId });
this.env.model.dispatch("CUT");
await this.env.clipboard.write(this.env.model.getters.getClipboardContent());
},
},
{
id: "reset_size",
name: _lt("Reset size"),
action: () => {
const size = this.env.model.getters.getImageSize(this.figureId);
const { height, width } = getMaxFigureSize(this.env.model.getters, size);
this.env.model.dispatch("UPDATE_FIGURE", {
sheetId: this.env.model.getters.getActiveSheetId(),
id: this.figureId,
height,
width,
});
},
},
{
id: "delete",
name: _lt("Delete image"),
description: "delete",
action: () => {
this.env.model.dispatch("DELETE_FIGURE", {
sheetId: this.env.model.getters.getActiveSheetId(),
id: this.figureId,
});
},
},
]);

onContextMenu(ev: MouseEvent) {
const position = {
x: this.position.x + ev.offsetX,
y: this.position.y + ev.offsetY,
};
this.openContextMenu(position);
}

showMenu() {
const { x, y, width } = this.menuButtonRect;
const menuPosition = {
x: x >= MENU_WIDTH ? x - MENU_WIDTH : x + width,
y: y,
};
this.openContextMenu(menuPosition);
}

private openContextMenu(position: DOMCoordinates) {
this.menuState.isOpen = true;
this.menuState.position = position;
}
static components = {};

// ---------------------------------------------------------------------------
// Getters
Expand Down
22 changes: 1 addition & 21 deletions src/components/figures/figure_image/figure_image.xml
Original file line number Diff line number Diff line change
@@ -1,25 +1,5 @@
<templates>
<t t-name="o-spreadsheet-ImageFigure" owl="1">
<div class="o-figure-menu" t-if="!env.isDashboard()">
<div
class="o-figure-menu-item"
t-on-click="showMenu"
t-ref="menuButton"
t-on-contextmenu.prevent.stop="showMenu">
<t t-call="o-spreadsheet-Icon.LIST"/>
</div>
</div>
<img
t-ref="o-image"
t-att-src="getImagePath"
class="w-100 h-100"
t-on-contextmenu.prevent.stop="(ev) => !env.isDashboard() and this.onContextMenu(ev)"
/>
<Menu
t-if="menuState.isOpen"
position="menuState.position"
menuItems="menuItems"
onClose="() => this.menuState.isOpen=false"
/>
<img t-att-src="getImagePath" class="w-100 h-100"/>
</t>
</templates>
Loading

0 comments on commit c8dd315

Please sign in to comment.