File : dialogs/baseDialog/DockableBaseDialog.js

1
/*
2
Copyright - 2017 2023 - wwwouaiebe - Contact: https://www.ouaie.be/
3
4
This  program is free software;
5
you can redistribute it and/or modify it under the terms of the
6
GNU General Public License as published by the Free Software Foundation;
7
either version 3 of the License, or any later version.
8
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
GNU General Public License for more details.
13
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
*/
18
/*
19
Changes:
20
    - v4.0.0:
21
        - created from v3.6.0
22
Doc reviewed 202208
23
 */
24
25
import NonModalBaseDialog from './NonModalBaseDialog.js';
26
import DockableBaseDialogMover from './DockableBaseDialogMover.js';
27
import theConfig from '../../data/Config.js';
28
import BaseContextMenu from '../../contextMenus/baseContextMenu/BaseContextMenu.js';
29
import { ZERO } from '../../main/Constants.js';
30
31
/* ------------------------------------------------------------------------------------------------------------------------- */
32
/**
33
Base class used for dockable dialogs
34
*/
35
/* ------------------------------------------------------------------------------------------------------------------------- */
36
37
class DockableBaseDialog extends NonModalBaseDialog {
38
39
    /**
40
    The default X position in pixels for the dialog
41
    @type {?Number}
42
    */
43
44
    #dialogX;
45
46
    /**
47
    The default Y position in pixels for the dialog
48
    @type {?Number}
49
    */
50
51
    #dialogY;
52
53
    /**
54
    A timer id for the mouse leave event listener
55
    @type {?Number}
56
    */
57
58
    #mouseLeaveTimerId;
59
60
    /**
61
    The mover used by the dialog
62
    @type {DockableBaseDialogMover}
63
    */
64
65
    #dockableBaseDialogMover;
66
67
    /**
68
    The last mouse event time stamp. Used to detect a mouseenter event directly followed by a click event
69
    on touch devices
70
    @type {Number}
71
    */
72
73
    #lastMouseEventTimestamp;
74
75
    /**
76
    A flag to store the visibility of the dialog
77
    @type {boolean}
78
    */
79
80
    #isShow;
81
82
    /**
83
    The max delay between a mouseenter and a click event to consider the two events as a single event
84
    @type {Number}
85
    */
86
87
    // eslint-disable-next-line no-magic-numbers
88
    static get #MOUSE_EVENT_MAX_DELAY ( ) { return 100; }
89
90
    /**
91
    The minimal timeout for the mouse leave event
92
    @type {Number}
93
    */
94
95
    // eslint-disable-next-line no-magic-numbers
96
    static get #MIN_MOUSE_LEAVE_TIMEOUT ( ) { return 1500; }
97
98
    /**
99
    Hide the content of the dialog. Used by the timer on mouseLeave
100
    */
101
102
    #hideContent ( ) {
103
        if ( this.mover.dialogDocked ) {
104
            if ( BaseContextMenu.isActive ) {
105
                this.#mouseLeaveTimerId = setTimeout (
106
                    ( ) => { this.#hideContent ( ); },
107
                    Math.max ( DockableBaseDialog.#MIN_MOUSE_LEAVE_TIMEOUT, theConfig.dockableBaseDialog.timeout )
108
                );
109
            }
110
            else {
111
                this.mover.dialogHTMLElement.classList.add (
112
                    'TravelNotes-DockableBaseDialog-HiddenContent'
113
                );
114
            }
115
        }
116
    }
117
118
    /**
119
    mouse enter on the dialog event listener
120
    @param {Event} mouseEvent The event to handle
121
    */
122
123
    #mouseEnterDialogEL ( mouseEvent ) {
124
        this.#lastMouseEventTimestamp = mouseEvent.timeStamp;
125
        if ( this.#mouseLeaveTimerId ) {
126
            clearTimeout ( this.#mouseLeaveTimerId );
127
            this.#mouseLeaveTimerId = null;
128
        }
129
        if ( this.mover.dialogDocked ) {
130
            this.mover.dialogHTMLElement.classList.remove ( 'TravelNotes-DockableBaseDialog-HiddenContent' );
131
        }
132
    }
133
134
    /**
135
    mouse leave the dialog event listener
136
    */
137
138
    #mouseLeaveDialogEL ( ) {
139
        if ( this.mover.dialogDocked ) {
140
            this.#mouseLeaveTimerId = setTimeout (
141
                ( ) => { this.#hideContent ( ); },
142
                Math.max ( DockableBaseDialog.#MIN_MOUSE_LEAVE_TIMEOUT, theConfig.dockableBaseDialog.timeout )
143
            );
144
        }
145
    }
146
147
    /**
148
    Click on the top bar event listener
149
    @param {Event} clickEvent The event to handle
150
    */
151
152
    #topBarClickEL ( clickEvent ) {
153
        clickEvent.preventDefault ( );
154
        if ( DockableBaseDialog.#MOUSE_EVENT_MAX_DELAY > clickEvent.timeStamp - this.#lastMouseEventTimestamp ) {
155
            return;
156
        }
157
        if ( this.mover.dialogDocked ) {
158
            this.mover.dialogHTMLElement.classList.toggle ( 'TravelNotes-DockableBaseDialog-HiddenContent' );
159
        }
160
    }
161
162
    /**
163
    The constructor
164
    @param {Number} dialogX The default X position in pixels for the dialog
165
    @param {Number} dialogY The default Y position in pixels for the dialog
166
    */
167
168
    constructor ( dialogX, dialogY ) {
169
        super ( );
170
        this.#dialogX = dialogX;
171
        this.#dialogY = dialogY;
172
        this.#mouseLeaveTimerId = null;
173
        this.#dockableBaseDialogMover = null;
174
        this.#lastMouseEventTimestamp = ZERO;
175
        this.#isShow = false;
176
    }
177
178
    /**
179
    Get the mover object used with this dialog. Create the object if needed.
180
    Overload of the base class get mover ( )
181
    @type {DockableBaseDialogMover}
182
    */
183
184
    get mover ( ) {
185
        return this.#dockableBaseDialogMover ?
186
            this.#dockableBaseDialogMover :
187
            this.#dockableBaseDialogMover = new DockableBaseDialogMover ( );
188
    }
189
190
    /**
191
    Overload of the base class method onCancel ( ). Close the dialog
192
    */
193
194
    onCancel ( ) {
195
        super.onCancel ( );
196
        this.#isShow = false;
197
        if ( this.#dockableBaseDialogMover ) {
198
            this.#dockableBaseDialogMover = null;
199
        }
200
    }
201
202
    /**
203
    Show the dialog. Overload of the base class show method
204
    */
205
206
    show ( ) {
207
        if ( this.#isShow ) {
208
            return;
209
        }
210
        super.show ( );
211
        this.addCssClass ( 'TravelNotes-DockableBaseDialog' );
212
        this.updateContent ( );
213
        if ( null !== this.#dialogX && null !== this.#dialogY ) {
214
            this.mover.moveDialogTo ( this.#dialogX, this.#dialogY );
215
            this.#dialogX = null;
216
            this.#dialogY = null;
217
        }
218
        else {
219
            this.mover.moveDialogToLastPosition ( );
220
        }
221
        this.mover.dialogHTMLElement.addEventListener (
222
            'mouseenter',
223
            mouseEvent => this.#mouseEnterDialogEL ( mouseEvent ),
224
            false
225
        );
226
227
        if ( theConfig.dockableBaseDialog.hideOnMouseLeave ) {
228
            this.mover.dialogHTMLElement.addEventListener (
229
                'mouseleave',
230
                ( ) => this.#mouseLeaveDialogEL ( ),
231
                false
232
            );
233
        }
234
235
        this.mover.topBarHTMLElement.addEventListener (
236
            'click',
237
            clickEvent => this.#topBarClickEL ( clickEvent ),
238
            false
239
        );
240
241
        if ( this.mover.dialogDocked ) {
242
            this.mover.dialogHTMLElement.classList.add ( 'TravelNotes-DockableBaseDialog-HiddenContent' );
243
        }
244
        this.#isShow = true;
245
    }
246
247
}
248
249
export default DockableBaseDialog;
250
251
/* --- End of file --------------------------------------------------------------------------------------------------------- */
252