22
33import { useBus } from "../bus_hook" ;
44import { registry } from "../registry" ;
5+ import { useService } from "../service_hook" ;
56import { Popover } from "./popover" ;
67
78const { Component } = owl ;
89const { EventBus } = owl . core ;
9- const { useState } = owl . hooks ;
10+ const { onWillUnmount } = owl . hooks ;
1011const { xml } = owl . tags ;
1112
12- const bus = new EventBus ( ) ;
13-
1413export class KeyAlreadyExistsError extends Error {
1514 constructor ( key ) {
1615 super ( `PopoverManager already contains key "${ key } "` ) ;
@@ -25,50 +24,56 @@ export class KeyNotFoundError extends Error {
2524
2625export 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`
99104registry . category ( "main_components" ) . add ( "PopoverManager" , PopoverManager ) ;
100105
101106export 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
130174registry . category ( "services" ) . add ( "popover" , popoverService ) ;
0 commit comments