@@ -51,13 +51,15 @@ class ContextMenu implements IREWMenu.IContextMenu {
51
51
} else {
52
52
this . container = document . createElement ( 'div' ) ;
53
53
this . container . setAttribute ( 'data-rewm-contextmenu-container' , id ) ;
54
+ this . container . setAttribute ( 'tabindex' , '0' ) ;
54
55
document . body . appendChild ( this . container ) ;
55
56
}
56
57
57
58
// set style of this.container
58
59
this . container . style . position = 'absolute' ;
59
60
this . container . style . left = containerLeft + 'px' ;
60
61
this . container . style . top = containerTop + 'px' ;
62
+ this . container . style . outline = '0' ;
61
63
62
64
if ( this . container ) {
63
65
this . visible = true ;
@@ -69,15 +71,21 @@ class ContextMenu implements IREWMenu.IContextMenu {
69
71
}
70
72
71
73
onClickItem : IREWMenu . OnClickItem = ( menuItem , w , e ) => {
72
- const { type = 'normal' , enabled = true , visible = true } = menuItem ;
74
+ const { type = 'normal' , enabled = true } = menuItem ;
73
75
74
76
if ( enabled ) {
77
+ if ( ! menuItem . submenu && menuItem . click ) {
78
+ menuItem . click ( menuItem , w , e ) ;
79
+ }
80
+
75
81
if ( type === 'checkbox' ) {
76
82
menuItem . checked = ! menuItem . checked ;
83
+ this . render ( ) ;
84
+ } else {
85
+ // 메뉴가 클릭되었다는 것을 인지하는 곳.
86
+ this . visible = false ;
77
87
}
78
88
}
79
- // 메뉴가 클릭되었다는 것은 인지하는 곳.
80
- this . visible = false ;
81
89
} ;
82
90
83
91
// document.body에서 마우스 다운이 일어난 경우 contextMenu안쪽이 클릭된 것이지 바깥쪽에서 마우스 다운이 일어 난 건지 체크.
@@ -88,9 +96,123 @@ class ContextMenu implements IREWMenu.IContextMenu {
88
96
}
89
97
} ;
90
98
91
- onKeyDownWindow = ( e : KeyboardEvent ) => {
92
- if ( e . which === 27 ) {
93
- this . visible = false ;
99
+ getCurrentHoveredIndex = ( ) : number [ ] => {
100
+ const currentHoveredIndex : number [ ] = [ ] ;
101
+ const findOpenedItem = ( items : IREWMenu . IMenuItem [ ] ) => {
102
+ const findex = items . findIndex ( item => item . opened ) ;
103
+ if ( findex > - 1 ) {
104
+ currentHoveredIndex . push ( findex ) ;
105
+ if ( items [ findex ] . submenu ) {
106
+ findOpenedItem ( items [ findex ] . submenu ! ) ;
107
+ }
108
+ }
109
+ } ;
110
+ findOpenedItem ( this . menuItems ) ;
111
+ return currentHoveredIndex ;
112
+ } ;
113
+
114
+ moveHoveredIndex = ( type : 'UP' | 'DOWN' | 'LEFT' | 'RIGHT' ) => {
115
+ const currentHoveredIndexes = this . getCurrentHoveredIndex ( ) ;
116
+ let targetItems = this . menuItems ;
117
+ let targetItemsHoveredIndex = currentHoveredIndexes [ 0 ] ;
118
+
119
+ currentHoveredIndexes . forEach ( ( v , i ) => {
120
+ if ( i < currentHoveredIndexes . length - 1 && targetItems [ v ] . submenu ) {
121
+ targetItems = targetItems [ v ] . submenu ! ;
122
+ targetItemsHoveredIndex = currentHoveredIndexes [ i + 1 ] ;
123
+ }
124
+ } ) ;
125
+ if ( type === 'UP' || type === 'DOWN' ) {
126
+ targetItems . forEach ( item => ( item . opened = false ) ) ;
127
+
128
+ let ing = true ;
129
+ do {
130
+ const nextMenuIndex =
131
+ type === 'DOWN'
132
+ ? targetItemsHoveredIndex === undefined
133
+ ? 0
134
+ : targetItemsHoveredIndex + 1
135
+ : targetItemsHoveredIndex === undefined
136
+ ? targetItems . length - 1
137
+ : targetItemsHoveredIndex - 1 ;
138
+ const nextMenu = targetItems [ nextMenuIndex ] ;
139
+ if ( ! nextMenu ) {
140
+ targetItems [ targetItemsHoveredIndex ] . opened = true ;
141
+ ing = false ;
142
+ break ;
143
+ }
144
+ if ( nextMenu . type === 'separator' || nextMenu . visible === false ) {
145
+ targetItemsHoveredIndex = nextMenuIndex ;
146
+ continue ;
147
+ }
148
+ targetItems [ nextMenuIndex ] . opened = true ;
149
+ ing = false ;
150
+ } while ( ing ) ;
151
+
152
+ this . render ( ) ;
153
+ } else if ( type === 'RIGHT' ) {
154
+ if ( targetItemsHoveredIndex === undefined ) targetItemsHoveredIndex = 0 ;
155
+ targetItems [ targetItemsHoveredIndex ] . submenu ?. forEach (
156
+ item => ( item . opened = false ) ,
157
+ ) ;
158
+ const submenu = targetItems [ targetItemsHoveredIndex ] . submenu ;
159
+ if ( submenu ) {
160
+ submenu [ 0 ] . opened = true ;
161
+ }
162
+ this . render ( ) ;
163
+ } else if ( type === 'LEFT' ) {
164
+ targetItems . forEach ( item => ( item . opened = false ) ) ;
165
+ this . render ( ) ;
166
+ }
167
+ } ;
168
+
169
+ handleClickItem = ( e : KeyboardEvent ) => {
170
+ let menu : IREWMenu . IMenuItem | undefined ;
171
+ const findOpenedItem = ( items : IREWMenu . IMenuItem [ ] ) => {
172
+ const findex = items . findIndex ( item => item . opened ) ;
173
+ if ( findex > - 1 ) {
174
+ menu = items [ findex ] ;
175
+ if ( items [ findex ] . submenu ) {
176
+ findOpenedItem ( items [ findex ] . submenu ! ) ;
177
+ }
178
+ }
179
+ } ;
180
+ findOpenedItem ( this . menuItems ) ;
181
+
182
+ if ( menu ) {
183
+ this . onClickItem ( menu , window ) ;
184
+ }
185
+ } ;
186
+
187
+ onKeyDown = ( e : KeyboardEvent ) => {
188
+ e . preventDefault ( ) ;
189
+
190
+ switch ( e . key ) {
191
+ case 'Down' : // IE/Edge specific value
192
+ case 'ArrowDown' :
193
+ this . moveHoveredIndex ( 'DOWN' ) ;
194
+ break ;
195
+ case 'Up' : // IE/Edge specific value
196
+ case 'ArrowUp' :
197
+ this . moveHoveredIndex ( 'UP' ) ;
198
+ break ;
199
+ case 'Left' : // IE/Edge specific value
200
+ case 'ArrowLeft' :
201
+ this . moveHoveredIndex ( 'LEFT' ) ;
202
+ break ;
203
+ case 'Right' : // IE/Edge specific value
204
+ case 'ArrowRight' :
205
+ this . moveHoveredIndex ( 'RIGHT' ) ;
206
+ break ;
207
+ case 'Enter' :
208
+ this . handleClickItem ( e ) ;
209
+ break ;
210
+ case 'Esc' : // IE/Edge specific value
211
+ case 'Escape' :
212
+ this . visible = false ;
213
+ break ;
214
+ default :
215
+ return ; // Quit when this doesn't handle the key event.
94
216
}
95
217
} ;
96
218
@@ -115,11 +237,14 @@ class ContextMenu implements IREWMenu.IContextMenu {
115
237
) ;
116
238
117
239
if ( this . visible ) {
240
+ this . container . focus ( ) ;
118
241
document . body . addEventListener ( 'mousedown' , this . onMousedownBody ) ;
119
- window . addEventListener ( 'keydown' , this . onKeyDownWindow ) ;
242
+ this . container . addEventListener ( 'keydown' , this . onKeyDown ) ;
120
243
} else {
121
244
document . body . removeEventListener ( 'mousedown' , this . onMousedownBody ) ;
122
- window . removeEventListener ( 'keydown' , this . onKeyDownWindow ) ;
245
+ this . container . removeEventListener ( 'keydown' , this . onKeyDown ) ;
246
+ this . container . blur ( ) ;
247
+ this . container . remove ( ) ;
123
248
}
124
249
}
125
250
}
0 commit comments