@@ -8,6 +8,7 @@ import type {
88 Ship ,
99} from '../../shared/types' ;
1010import { byId , el , hide , show , visible } from '../dom' ;
11+ import { ACTION_BUTTON_IDS , STATIC_BUTTON_BINDINGS } from './button-bindings' ;
1112import type { UIEvent } from './events' ;
1213import { canAddFleetShip , getFleetCartView , getFleetShopView } from './fleet' ;
1314import {
@@ -56,20 +57,7 @@ export class UIManager {
5657 private playerId : number = - 1 ;
5758 private layoutSyncFrame : number | null = null ;
5859
59- private readonly actionButtonIds = [
60- 'undoBtn' ,
61- 'confirmBtn' ,
62- 'launchMineBtn' ,
63- 'launchTorpedoBtn' ,
64- 'launchNukeBtn' ,
65- 'emplaceBaseBtn' ,
66- 'skipOrdnanceBtn' ,
67- 'attackBtn' ,
68- 'fireBtn' ,
69- 'skipCombatBtn' ,
70- 'skipLogisticsBtn' ,
71- 'confirmTransfersBtn' ,
72- ] ;
60+ private readonly actionButtonIds = ACTION_BUTTON_IDS ;
7361
7462 onEvent : ( ( event : UIEvent ) => void ) | null = null ;
7563
@@ -100,20 +88,7 @@ export class UIManager {
10088 this . chatInput = byId ( 'chatInput' ) as HTMLInputElement ;
10189 this . fleetBuildingEl = byId ( 'fleetBuilding' ) ;
10290
103- this . chatInput . addEventListener ( 'keydown' , ( e ) => {
104- // Prevent game keyboard shortcuts while
105- // typing
106- e . stopPropagation ( ) ;
107-
108- if ( e . key === 'Enter' ) {
109- const text = this . chatInput . value . trim ( ) ;
110-
111- if ( text && this . onEvent ) {
112- this . onEvent ( { type : 'chat' , text } ) ;
113- this . chatInput . value = '' ;
114- }
115- }
116- } ) ;
91+ this . bindChatInput ( ) ;
11792
11893 const mobileQuery = window . matchMedia ( '(max-width: 760px)' ) ;
11994 this . isMobile = mobileQuery . matches ;
@@ -133,7 +108,42 @@ export class UIManager {
133108 this . handleViewportResize ,
134109 ) ;
135110
136- // Wire up buttons
111+ this . bindMenuControls ( ) ;
112+ this . bindDifficultyButtons ( ) ;
113+ // Generate scenario buttons from data
114+ this . buildScenarioList ( ) ;
115+ this . bindJoinControls ( ) ;
116+ this . bindCopyButton ( ) ;
117+ this . bindStaticButtons ( ) ;
118+ this . bindLogControls ( ) ;
119+ }
120+
121+ private emit ( event : UIEvent ) {
122+ this . onEvent ?.( event ) ;
123+ }
124+
125+ private bindChatInput ( ) {
126+ this . chatInput . addEventListener ( 'keydown' , ( e ) => {
127+ // Prevent game keyboard shortcuts while
128+ // typing
129+ e . stopPropagation ( ) ;
130+
131+ if ( e . key !== 'Enter' ) {
132+ return ;
133+ }
134+
135+ const text = this . chatInput . value . trim ( ) ;
136+
137+ if ( ! text ) {
138+ return ;
139+ }
140+
141+ this . emit ( { type : 'chat' , text } ) ;
142+ this . chatInput . value = '' ;
143+ } ) ;
144+ }
145+
146+ private bindMenuControls ( ) {
137147 byId ( 'createBtn' ) . addEventListener ( 'click' , ( ) => {
138148 this . showScenarioSelect ( ) ;
139149 } ) ;
@@ -143,70 +153,60 @@ export class UIManager {
143153 this . showScenarioSelect ( ) ;
144154 } ) ;
145155
146- // Difficulty buttons
147- for ( const btn of Array . from (
148- document . querySelectorAll ( '.btn-difficulty' ) ,
149- ) ) {
156+ byId ( 'backBtn' ) . addEventListener ( 'click' , ( ) => {
157+ this . emit ( { type : 'backToMenu' } ) ;
158+ this . showMenu ( ) ;
159+ } ) ;
160+ }
161+
162+ private bindDifficultyButtons ( ) {
163+ const buttons = Array . from (
164+ document . querySelectorAll < HTMLElement > ( '.btn-difficulty' ) ,
165+ ) ;
166+
167+ for ( const btn of buttons ) {
150168 btn . addEventListener ( 'click' , ( e : Event ) => {
151169 e . stopPropagation ( ) ;
152170
153- const diff = ( btn as HTMLElement ) . dataset . difficulty as
154- | 'easy'
155- | 'normal'
156- | 'hard' ;
171+ const diff = btn . dataset . difficulty as 'easy' | 'normal' | 'hard' ;
157172 this . aiDifficulty = diff ;
158173
159- // Update active state
160- for ( const b of Array . from (
161- document . querySelectorAll ( '.btn-difficulty' ) ,
162- ) ) {
163- b . classList . remove ( 'active' ) ;
174+ for ( const button of buttons ) {
175+ button . classList . remove ( 'active' ) ;
164176 }
165177
166178 btn . classList . add ( 'active' ) ;
167179 } ) ;
168180 }
181+ }
169182
170- // Generate scenario buttons from data
171- this . buildScenarioList ( ) ;
183+ private submitJoin ( rawValue : string ) {
184+ const parsed = parseJoinInput ( rawValue , CODE_LENGTH ) ;
172185
173- byId ( 'backBtn' ) . addEventListener ( 'click' , ( ) => {
174- this . onEvent ?.( { type : 'backToMenu' } ) ;
175- this . showMenu ( ) ;
186+ if ( ! parsed ) {
187+ return ;
188+ }
189+
190+ this . emit ( {
191+ type : 'join' ,
192+ code : parsed . code ,
193+ playerToken : parsed . playerToken ,
176194 } ) ;
195+ }
177196
197+ private bindJoinControls ( ) {
178198 byId ( 'joinBtn' ) . addEventListener ( 'click' , ( ) => {
179- const parsed = parseJoinInput (
180- ( byId ( 'codeInput' ) as HTMLInputElement ) . value ,
181- CODE_LENGTH ,
182- ) ;
183-
184- if ( parsed ) {
185- this . onEvent ?.( {
186- type : 'join' ,
187- code : parsed . code ,
188- playerToken : parsed . playerToken ,
189- } ) ;
190- }
199+ this . submitJoin ( ( byId ( 'codeInput' ) as HTMLInputElement ) . value ) ;
191200 } ) ;
192201
193202 byId ( 'codeInput' ) . addEventListener ( 'keydown' , ( e ) => {
194203 if ( e . key === 'Enter' ) {
195- const parsed = parseJoinInput (
196- ( e . target as HTMLInputElement ) . value ,
197- CODE_LENGTH ,
198- ) ;
199-
200- if ( parsed ) {
201- this . onEvent ?.( {
202- type : 'join' ,
203- code : parsed . code ,
204- playerToken : parsed . playerToken ,
205- } ) ;
206- }
204+ this . submitJoin ( ( e . target as HTMLInputElement ) . value ) ;
207205 }
208206 } ) ;
207+ }
209208
209+ private bindCopyButton ( ) {
210210 byId ( 'copyBtn' ) . addEventListener ( 'click' , ( ) => {
211211 const code = byId ( 'gameCode' ) . textContent ;
212212 const url = `${ window . location . origin } /?code=${ code } ` ;
@@ -219,99 +219,38 @@ export class UIManager {
219219 } , 2000 ) ;
220220 } ) ;
221221 } ) ;
222+ }
222223
223- byId ( 'undoBtn' ) . addEventListener ( 'click' , ( ) =>
224- this . onEvent ?.( { type : 'undo' } ) ,
225- ) ;
226-
227- byId ( 'confirmBtn' ) . addEventListener ( 'click' , ( ) =>
228- this . onEvent ?.( { type : 'confirm' } ) ,
229- ) ;
230-
231- byId ( 'launchMineBtn' ) . addEventListener ( 'click' , ( ) =>
232- this . onEvent ?.( {
233- type : 'launchOrdnance' ,
234- ordType : 'mine' ,
235- } ) ,
236- ) ;
237-
238- byId ( 'launchTorpedoBtn' ) . addEventListener ( 'click' , ( ) =>
239- this . onEvent ?.( {
240- type : 'launchOrdnance' ,
241- ordType : 'torpedo' ,
242- } ) ,
243- ) ;
244-
245- byId ( 'launchNukeBtn' ) . addEventListener ( 'click' , ( ) =>
246- this . onEvent ?.( {
247- type : 'launchOrdnance' ,
248- ordType : 'nuke' ,
249- } ) ,
250- ) ;
251-
252- byId ( 'emplaceBaseBtn' ) . addEventListener ( 'click' , ( ) =>
253- this . onEvent ?.( { type : 'emplaceBase' } ) ,
254- ) ;
255-
256- byId ( 'skipOrdnanceBtn' ) . addEventListener ( 'click' , ( ) =>
257- this . onEvent ?.( { type : 'skipOrdnance' } ) ,
258- ) ;
259-
260- byId ( 'attackBtn' ) . addEventListener ( 'click' , ( ) =>
261- this . onEvent ?.( { type : 'attack' } ) ,
262- ) ;
263-
264- byId ( 'fireBtn' ) . addEventListener ( 'click' , ( ) =>
265- this . onEvent ?.( { type : 'fireAll' } ) ,
266- ) ;
267-
268- byId ( 'skipCombatBtn' ) . addEventListener ( 'click' , ( ) =>
269- this . onEvent ?.( { type : 'skipCombat' } ) ,
270- ) ;
271-
272- byId ( 'skipLogisticsBtn' ) . addEventListener ( 'click' , ( ) =>
273- this . onEvent ?.( {
274- type : 'skipLogistics' ,
275- } ) ,
276- ) ;
224+ private bindStaticButtons ( ) {
225+ for ( const binding of STATIC_BUTTON_BINDINGS ) {
226+ byId ( binding . id ) . addEventListener ( 'click' , ( ) => {
227+ this . emit ( binding . event ) ;
228+ } ) ;
229+ }
230+ }
277231
278- byId ( 'confirmTransfersBtn' ) . addEventListener ( 'click' , ( ) =>
279- this . onEvent ?.( {
280- type : 'confirmTransfers' ,
281- } ) ,
282- ) ;
232+ private setDesktopLogVisible ( visibleOnDesktop : boolean ) {
233+ this . logVisible = visibleOnDesktop ;
283234
284- byId ( 'rematchBtn' ) . addEventListener ( 'click' , ( ) =>
285- this . onEvent ?.( { type : 'rematch' } ) ,
286- ) ;
235+ const visibility = buildScreenVisibility ( 'hud' , this . logVisible ) ;
287236
288- byId ( 'exitBtn' ) . addEventListener ( 'click' , ( ) =>
289- this . onEvent ?. ( { type : 'exit' } ) ,
290- ) ;
237+ this . gameLogEl . style . display = visibility . gameLog ;
238+ this . logShowBtn . style . display = visibility . logShowBtn ;
239+ }
291240
292- // Game log toggle
241+ private bindLogControls ( ) {
293242 byId ( 'logToggleBtn' ) . addEventListener ( 'click' , ( ) => {
294243 if ( this . isMobile ) {
295244 this . collapseMobileLog ( ) ;
296245
297246 return ;
298247 }
299248
300- this . logVisible = false ;
301-
302- const visibility = buildScreenVisibility ( 'hud' , this . logVisible ) ;
303-
304- this . gameLogEl . style . display = visibility . gameLog ;
305- this . logShowBtn . style . display = visibility . logShowBtn ;
249+ this . setDesktopLogVisible ( false ) ;
306250 } ) ;
307251
308252 this . logShowBtn . addEventListener ( 'click' , ( ) => {
309- this . logVisible = true ;
310-
311- const visibility = buildScreenVisibility ( 'hud' , this . logVisible ) ;
312-
313- this . gameLogEl . style . display = visibility . gameLog ;
314- this . logShowBtn . style . display = visibility . logShowBtn ;
253+ this . setDesktopLogVisible ( true ) ;
315254 } ) ;
316255 }
317256
0 commit comments