@@ -64,9 +64,52 @@ const chatgpt = {
64
64
// [ title/msg = strings, btns = [named functions], checkbox = named function, width (px) = int ] = optional
65
65
// * Spaces are inserted into button labels by parsing function names in camel/kebab/snake case
66
66
67
+ // Init env context
67
68
const scheme = chatgpt . isDarkMode ( ) ? 'dark' : 'light' ,
68
69
isMobile = chatgpt . browser . isMobile ( ) ;
69
70
71
+ // Define event handlers
72
+ const clickHandler = event => { // explicitly defined to support removal post-dismissal
73
+ if ( event . target == event . currentTarget || event . target . closest ( '[class*="-close-btn]' ) ) dismissAlert ( ) }
74
+ const keyHandler = event => { // to dismiss active alert
75
+ if ( / ^ (?: | S p a c e | E n t e r | R e t u r n | E s c ) / . test ( event . key ) || [ 32 , 13 , 27 ] . includes ( event . keyCode ) ) {
76
+ for ( const alertId of alertQueue ) { // look to handle only if triggering alert is active
77
+ const alert = document . getElementById ( alertId )
78
+ if ( alert && alert . style . display !== 'none' ) { // active alert found
79
+ if ( event . key . includes ( 'Esc' ) || event . keyCode == 27 ) // esc pressed
80
+ dismissAlert ( ) // dismiss alert & do nothing
81
+ else if ( / ^ (?: | S p a c e | E n t e r | R e t u r n ) / . test ( event . key ) || [ 32 , 13 ] . includes ( event . keyCode ) ) {
82
+ const mainButton = alert . querySelector ( '.modal-buttons' ) . lastChild // look for main button
83
+ if ( mainButton ) { mainButton . click ( ) ; event . preventDefault ( ) } // click if found
84
+ } return
85
+ } } } }
86
+ const dragHandlers = {
87
+ mousedown ( event ) { // find modal, attach listeners, init XY offsets
88
+ if ( event . button != 0 ) return // prevent non-left-click drag
89
+ if ( getComputedStyle ( event . target ) . cursor == 'pointer' ) return // prevent drag on interactive elems
90
+ chatgpt . draggableElem = event . currentTarget
91
+ chatgpt . draggableElem . style . cursor = 'grabbing'
92
+ event . preventDefault ( ) ; // prevent sub-elems like icons being draggable
93
+ [ 'mousemove' , 'mouseup' ] . forEach ( event => document . addEventListener ( event , dragHandlers [ event ] ) )
94
+ const draggableElemRect = chatgpt . draggableElem . getBoundingClientRect ( )
95
+ dragHandlers . offsetX = event . clientX - draggableElemRect . left + 21
96
+ dragHandlers . offsetY = event . clientY - draggableElemRect . top + 12
97
+ } ,
98
+ mousemove ( event ) { // drag modal
99
+ if ( chatgpt . draggableElem ) {
100
+ const newX = event . clientX - dragHandlers . offsetX ,
101
+ newY = event . clientY - dragHandlers . offsetY
102
+ Object . assign ( chatgpt . draggableElem . style , { left : `${ newX } px` , top : `${ newY } px` } )
103
+ }
104
+ } ,
105
+ mouseup ( ) { // remove listeners, reset chatgpt.draggableElem
106
+ chatgpt . draggableElem . style . cursor = 'inherit' ;
107
+ [ 'mousemove' , 'mouseup' ] . forEach ( event =>
108
+ document . removeEventListener ( event , dragHandlers [ event ] ) )
109
+ chatgpt . draggableElem = null
110
+ }
111
+ }
112
+
70
113
// Create modal parent/children elements
71
114
const modalContainer = document . createElement ( 'div' ) ;
72
115
modalContainer . id = Math . floor ( chatgpt . randomFloat ( ) * 1000000 ) + Date . now ( ) ;
@@ -96,6 +139,7 @@ const chatgpt = {
96
139
97
140
// Alert styles
98
141
+ '.chatgpt-modal > div {'
142
+ + 'position: absolute ;' // to be click-draggable
99
143
+ 'opacity: 0 ;' // to fade-in
100
144
+ `border: 1px solid ${ scheme == 'dark' ? 'white' : '#b5b5b5' } ;`
101
145
+ `color: ${ scheme == 'dark' ? 'white' : 'black' } ;`
@@ -231,26 +275,11 @@ const chatgpt = {
231
275
} , 100 ) // delay for transition fx
232
276
}
233
277
234
- // Define click/key handlers
235
- const clickHandler = event => { // explicitly defined to support removal post-dismissal
236
- if ( event . target == event . currentTarget || event . target . closest ( '[class*="-close-btn]' ) ) dismissAlert ( ) ; } ;
237
- const keyHandler = event => { // to dismiss active alert
238
- if ( / ^ (?: | S p a c e | E n t e r | R e t u r n | E s c ) / . test ( event . key ) || [ 32 , 13 , 27 ] . includes ( event . keyCode ) ) {
239
- for ( const alertId of alertQueue ) { // look to handle only if triggering alert is active
240
- const alert = document . getElementById ( alertId ) ;
241
- if ( alert && alert . style . display !== 'none' ) { // active alert found
242
- if ( event . key . includes ( 'Esc' ) || event . keyCode == 27 ) // esc pressed
243
- dismissAlert ( ) ; // dismiss alert & do nothing
244
- else if ( [ ' ' , 'Spacebar' , 'Enter' , 'Return' ] . includes ( event . key ) || [ 32 , 13 ] . includes ( event . keyCode ) ) { // space/enter pressed
245
- const mainButton = alert . querySelector ( '.modal-buttons' ) . lastChild ; // look for main button
246
- if ( mainButton ) { mainButton . click ( ) ; event . preventDefault ( ) ; } // click if found
247
- } return ;
248
- } } } } ;
249
-
250
- // Add listeners to dismiss alert
278
+ // Add listeners
251
279
const dismissElems = [ modalContainer , closeBtn , closeSVG , dismissBtn ] ;
252
280
dismissElems . forEach ( elem => elem . onclick = clickHandler ) ;
253
281
document . addEventListener ( 'keydown' , keyHandler ) ;
282
+ modal . onmousedown = dragHandlers . mousedown // enable click-dragging
254
283
255
284
// Define alert dismisser
256
285
const dismissAlert = ( ) => {
0 commit comments