Skip to content

Commit ee02bd0

Browse files
mcm-odooaab-odoo
authored andcommitted
[IMP] web: improve code of popover
Popover services: - move bus from file scope into the service scope - add "specializeForComponent" to add some logics when component is unmounted - parameters passed to the manager isn't stored in state anymore to prevent props to be proxified. Popover tests: - remove a todo comment - prettify template strings - fix "Recompute position" test Popover services tests: - extract PseudoWebClient creation to lighten tests - add test related to "specializeForComponent" Doc updated
1 parent 87154fa commit ee02bd0

File tree

6 files changed

+573
-355
lines changed

6 files changed

+573
-355
lines changed

addons/web/static/src/core/popover/popover.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ Popover.props = {
293293
* @param {HTMLElement} popoverElement The popover element
294294
* @param {HTMLElement} targetElement The target element, to which
295295
* the popover will be visually "bound"
296-
* @param {integer} [margin=16] Minimal accepted margin from the border
296+
* @param {number} [margin=16] Minimal accepted margin from the border
297297
* of the viewport.
298298
* @returns {Object}
299299
*/

addons/web/static/src/core/popover/popover_service.js

Lines changed: 75 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22

33
import { useBus } from "../bus_hook";
44
import { registry } from "../registry";
5+
import { useService } from "../service_hook";
56
import { Popover } from "./popover";
67

78
const { Component } = owl;
89
const { EventBus } = owl.core;
9-
const { useState } = owl.hooks;
10+
const { onWillUnmount } = owl.hooks;
1011
const { xml } = owl.tags;
1112

12-
const bus = new EventBus();
13-
1413
export class KeyAlreadyExistsError extends Error {
1514
constructor(key) {
1615
super(`PopoverManager already contains key "${key}"`);
@@ -25,50 +24,56 @@ export class KeyNotFoundError extends Error {
2524

2625
export class PopoverManager extends Component {
2726
setup() {
28-
this.popovers = useState({});
29-
this.nextId = 0;
27+
// do not include popover params in state to keep original popover props
28+
this.popovers = {};
3029

30+
const { bus } = useService("popover");
3131
useBus(bus, "ADD", this.addPopover);
3232
useBus(bus, "REMOVE", this.removePopover);
3333
}
3434

3535
/**
36-
* @param {Object} params
37-
* @param {string} [params.key]
38-
* @param {string} [params.content]
39-
* @param {any} [params.Component]
40-
* @param {Object} [params.props]
41-
* @param {Function} [params.onClose]
42-
* @param {boolean} [params.keepOnClose=false]
36+
* @param {Object} params
37+
* @param {string} params.key
38+
* @param {string} [params.content]
39+
* @param {any} [params.Component]
40+
* @param {Object} [params.props]
41+
* @param {(key: string) => void} [params.onClose]
42+
* @param {boolean} [params.keepOnClose=false]
4343
*/
4444
addPopover(params) {
45-
const key = params.key || this.nextId;
46-
if (this.popovers[key]) {
47-
throw new KeyAlreadyExistsError(key);
45+
if (params.key in this.popovers) {
46+
throw new KeyAlreadyExistsError(params.key);
4847
}
4948

50-
this.popovers[key] = Object.assign({ key }, params);
51-
this.nextId += 1;
49+
this.popovers[params.key] = params;
50+
this.render();
5251
}
5352
/**
54-
* @param {string | number} key
53+
* @param {string} key
5554
*/
5655
removePopover(key) {
57-
if (!this.popovers[key]) {
56+
if (!(key in this.popovers)) {
5857
throw new KeyNotFoundError(key);
5958
}
6059

6160
delete this.popovers[key];
61+
this.render();
6262
}
6363

6464
/**
65-
* @param {string | number} key
65+
* @param {string} key
6666
*/
6767
onPopoverClosed(key) {
68-
if (this.popovers[key].onClose) {
69-
this.popovers[key].onClose();
68+
if (!(key in this.popovers)) {
69+
// It can happen that the popover was removed manually just before this call
70+
return;
71+
}
72+
const popover = this.popovers[key];
73+
if (popover.onClose) {
74+
popover.onClose(key);
7075
}
71-
if (!this.popovers[key].keepOnClose) {
76+
if (!popover.keepOnClose) {
7277
this.removePopover(key);
7378
}
7479
}
@@ -99,21 +104,30 @@ PopoverManager.template = xml`
99104
registry.category("main_components").add("PopoverManager", PopoverManager);
100105

101106
export const popoverService = {
102-
start(env) {
107+
start() {
108+
let nextId = 0;
109+
const bus = new EventBus();
103110
return {
111+
bus,
104112
/**
105113
* Signals the manager to add a popover.
106114
*
107-
* @param {Object} params
108-
* @param {string} [params.key]
109-
* @param {string} [params.content]
110-
* @param {any} [params.Component]
111-
* @param {Object} [params.props]
112-
* @param {Function} [params.onClose]
113-
* @param {boolean} [params.keepOnClose=false]
115+
* @param {Object} params
116+
* @param {string} [params.key]
117+
* @param {string} [params.content]
118+
* @param {any} [params.Component]
119+
* @param {Object} [params.props]
120+
* @param {(key: string) => void} [params.onClose]
121+
* @param {boolean} [params.keepOnClose=false]
122+
* @returns {string}
114123
*/
115124
add(params) {
125+
if (!("key" in params)) {
126+
params.key = `popover_${nextId}`;
127+
nextId += 1;
128+
}
116129
bus.trigger("ADD", params);
130+
return params.key;
117131
},
118132
/**
119133
* Signals the manager to remove the popover with key = `key`.
@@ -125,6 +139,36 @@ export const popoverService = {
125139
},
126140
};
127141
},
142+
specializeForComponent(component, service) {
143+
const keys = new Set();
144+
onWillUnmount(function () {
145+
for (const key of keys) {
146+
service.remove(key);
147+
}
148+
keys.clear();
149+
});
150+
return Object.assign(Object.create(service), {
151+
add(params) {
152+
const newParams = Object.create(params);
153+
newParams.onClose = function (key) {
154+
if (!params.keepOnClose) {
155+
// manager will delete the popover if keepOnClose is falsy
156+
keys.delete(key);
157+
}
158+
if (params.onClose && component.__owl__.status !== 5 /* DESTROYED */) {
159+
params.onClose(key);
160+
}
161+
};
162+
const key = service.add(newParams);
163+
keys.add(key);
164+
return key;
165+
},
166+
remove(key) {
167+
keys.delete(key);
168+
service.remove(key);
169+
},
170+
});
171+
},
128172
};
129173

130174
registry.category("services").add("popover", popoverService);

0 commit comments

Comments
 (0)