1- import { VM } from "./main" ;
1+ export let VM : CollabVMClient | null = null ;
22import CollabVMClient from "./protocol/CollabVMClient" ;
33import { Format } from './format.js' ;
4+ import { elements } from "./main" ;
5+ import { TheI18n } from "./i18n/i18n" ;
6+ import TurnStatus from './protocol/TurnStatus.js' ;
7+ import * as kblayout from './keyboard/layout.js' ;
8+ import { User , chatMessage } from './protocol/User.js' ;
9+ import VoteStatus from './protocol/VoteStatus.js' ;
10+ import * as Config from "../../config.json" ;
411
512let expectedClose : boolean = false ;
613
7- async function openVM ( vm : typeof VM ) : Promise < void > {
14+
15+ let turnInterval : number | undefined = undefined ;
16+ let voteInterval : number | undefined = undefined ;
17+
18+ const enableOSK = ( enable : boolean ) => {
19+ const theme = `simple-keyboard hg-theme-default cvmDark ${ enable ? '' : 'cvmDisabled' } hg-layout-default` ;
20+ [ kblayout . keyboard , kblayout . keyboardControlPad , kblayout . keyboardArrows , kblayout . keyboardNumPad , kblayout . keyboardNumPadEnd ] . forEach ( ( part ) => {
21+ part . setOptions ( {
22+ theme : theme
23+ } ) ;
24+ } ) ;
25+
26+ if ( enable ) kblayout . updateOSKStyle ( ) ;
27+ } ;
28+
29+ export async function openVM ( elements :any , vm : typeof VM ) : Promise < void > {
830 // If there's an active VM it must be closed before opening another
931 if ( VM !== null ) return ;
1032 expectedClose = false ;
11- // Set hash*
33+ // Set hash
1234 //@ts -ignore
1335 location . hash = vm . id ;
1436 // Create the client
37+ //@ts -ignore
1538 VM = new CollabVMClient ( vm . url ) ;
1639
1740 // Register event listeners
18-
1941 VM ! . on ( 'chat' , ( username , message ) => chatMessage ( username , message ) ) ;
2042 VM ! . on ( 'adduser' , ( user ) => addUser ( user ) ) ;
2143 VM ! . on ( 'flag' , ( ) => flag ( ) ) ;
@@ -63,17 +85,21 @@ async function openVM(vm: typeof VM): Promise<void> {
6385 await VM ! . WaitForOpen ( ) ;
6486
6587 // Connect to node
88+ //@ts -ignore
6689 chatMessage ( '' , `<b>${ vm . id } </b><hr>` ) ;
6790 let username = Config . Auth . Enabled ? ( auth ! . account ?. username ?? null ) : localStorage . getItem ( 'username' ) ;
91+ //@ts -ignore
6892 let connected = await VM . connect ( vm . id , username ) ;
93+ //@ts -ignore
6994 elements . adminInputVMID . value = vm . id ;
95+ //@ts -ignore
7096 w . VMName = vm . id ;
7197 if ( ! connected ) {
72- // just give up
7398 closeVM ( ) ;
7499 throw new Error ( 'Failed to connect to node' ) ;
75100 }
76101 // Set the title
102+ //@ts -ignore
77103 document . title = Format ( '{0} - {1}' , vm . id , TheI18n . GetString ( I18nStringKey . kGeneric_CollabVM ) ) ;
78104 // Append canvas
79105 elements . vmDisplay . appendChild ( VM ! . canvas ) ;
@@ -83,7 +109,7 @@ async function openVM(vm: typeof VM): Promise<void> {
83109 return ;
84110}
85111
86- function closeVM ( ) {
112+ export function closeVM ( ) {
87113 if ( VM === null ) return ;
88114 expectedClose = true ;
89115 // Close the VM
@@ -131,3 +157,142 @@ function closeVM() {
131157 elements . accountDropdownMenuLink . style . display = "none" ;
132158 }
133159}
160+
161+ function addUser ( user : User ) {
162+ let olduser = users . find ( ( u ) => u . user === user ) ;
163+ if ( olduser !== undefined ) elements . userlist . removeChild ( olduser . element ) ;
164+ let tr = document . createElement ( 'tr' ) ;
165+ tr . setAttribute ( 'data-cvm-turn' , '-1' ) ;
166+ let td = document . createElement ( 'td' ) ;
167+ let flagSpan = document . createElement ( 'span' ) ;
168+ let usernameSpan = document . createElement ( 'span' ) ;
169+ flagSpan . classList . add ( "userlist-flag" ) ;
170+ usernameSpan . classList . add ( "userlist-username" ) ;
171+ td . appendChild ( flagSpan ) ;
172+ if ( user . countryCode !== null ) {
173+ flagSpan . innerHTML = getFlagEmoji ( user . countryCode ) ;
174+ flagSpan . title = TheI18n . getCountryName ( user . countryCode ) ;
175+ } ;
176+ td . appendChild ( usernameSpan ) ;
177+ usernameSpan . innerText = user . username ;
178+ switch ( user . rank ) {
179+ case Rank . Admin :
180+ tr . classList . add ( 'user-admin' ) ;
181+ break ;
182+ case Rank . Moderator :
183+ tr . classList . add ( 'user-moderator' ) ;
184+ break ;
185+ case Rank . Registered :
186+ tr . classList . add ( 'user-registered' ) ;
187+ break ;
188+ case Rank . Unregistered :
189+ tr . classList . add ( 'user-unregistered' ) ;
190+ break ;
191+ }
192+ if ( user . username === w . username ) tr . classList . add ( 'user-current' ) ;
193+ tr . appendChild ( td ) ;
194+ let u = { user : user , element : tr , usernameElement : usernameSpan , flagElement : flagSpan } ;
195+ if ( rank === Rank . Admin || rank === Rank . Moderator ) userModOptions ( u ) ;
196+ elements . userlist . appendChild ( tr ) ;
197+ if ( olduser !== undefined ) olduser . element = tr ;
198+ else users . push ( u ) ;
199+ elements . onlineusercount . innerHTML = VM ! . getUsers ( ) . length . toString ( ) ;
200+ }
201+
202+ function remUser ( user : User ) {
203+ let olduser = users . findIndex ( ( u ) => u . user === user ) ;
204+ if ( olduser !== undefined ) elements . userlist . removeChild ( users [ olduser ] . element ) ;
205+ elements . onlineusercount . innerHTML = VM ! . getUsers ( ) . length . toString ( ) ;
206+ users . splice ( olduser , 1 ) ;
207+ }
208+
209+ function flag ( ) {
210+ for ( let user of users . filter ( u => u . user . countryCode !== null ) ) {
211+ user . flagElement . innerHTML = getFlagEmoji ( user . user . countryCode ! ) ;
212+ user . flagElement . title = TheI18n . getCountryName ( user . user . countryCode ! ) ;
213+ }
214+ }
215+
216+ function userRenamed ( oldname : string , newname : string , selfrename : boolean ) {
217+ let user = users . find ( ( u ) => u . user . username === newname ) ;
218+ if ( user ) {
219+ user . usernameElement . innerHTML = newname ;
220+ }
221+ if ( selfrename ) {
222+ w . username = newname ;
223+ elements . username . innerText = newname ;
224+ localStorage . setItem ( 'username' , newname ) ;
225+ }
226+ }
227+
228+ function turnUpdate ( status : TurnStatus ) {
229+ // Clear all turn data
230+ turn = - 1 ;
231+ VM ! . canvas . classList . remove ( 'focused' , 'waiting' ) ;
232+ clearInterval ( turnInterval ) ;
233+ turnTimer = 0 ;
234+ for ( const user of users ) {
235+ user . element . classList . remove ( 'user-turn' , 'user-waiting' ) ;
236+ user . element . setAttribute ( 'data-cvm-turn' , '-1' ) ;
237+ }
238+ elements . turnBtnText . innerHTML = TheI18n . GetString ( I18nStringKey . kVMButtons_TakeTurn ) ;
239+ enableOSK ( false ) ;
240+
241+ if ( status . user !== null ) {
242+ let el = users . find ( ( u ) => u . user === status . user ) ! . element ;
243+ el ! . classList . add ( 'user-turn' ) ;
244+ el ! . setAttribute ( 'data-cvm-turn' , '0' ) ;
245+ }
246+ for ( const user of status . queue ) {
247+ let el = users . find ( ( u ) => u . user === user ) ! . element ;
248+ el ! . classList . add ( 'user-waiting' ) ;
249+ el . setAttribute ( 'data-cvm-turn' , status . queue . indexOf ( user ) . toString ( 10 ) ) ;
250+ }
251+ if ( status . user ?. username === w . username ) {
252+ turn = 0 ;
253+ turnTimer = status . turnTime ! / 1000 ;
254+ elements . turnBtnText . innerHTML = TheI18n . GetString ( I18nStringKey . kVMButtons_EndTurn ) ;
255+ VM ! . canvas . classList . add ( 'focused' ) ;
256+ enableOSK ( true ) ;
257+ }
258+ if ( status . queue . some ( ( u ) => u . username === w . username ) ) {
259+ turn = status . queue . findIndex ( ( u ) => u . username === w . username ) + 1 ;
260+ turnTimer = status . queueTime ! / 1000 ;
261+ elements . turnBtnText . innerHTML = TheI18n . GetString ( I18nStringKey . kVMButtons_EndTurn ) ;
262+ VM ! . canvas . classList . add ( 'waiting' ) ;
263+ }
264+ if ( turn === - 1 ) elements . turnstatus . innerText = '' ;
265+ else {
266+ //@ts -ignore
267+ turnInterval = setInterval ( ( ) => turnIntervalCb ( ) , 1000 ) ;
268+ setTurnStatus ( ) ;
269+ }
270+ sortUserList ( ) ;
271+ }
272+
273+ function voteUpdate ( status : VoteStatus ) {
274+ clearInterval ( voteInterval ) ;
275+ elements . voteResetPanel . style . display = 'block' ;
276+ elements . voteYesLabel . innerText = status . yesVotes . toString ( ) ;
277+ elements . voteNoLabel . innerText = status . noVotes . toString ( ) ;
278+ voteTimer = Math . floor ( status . timeToEnd / 1000 ) ;
279+ //@ts -ignore
280+ voteInterval = setInterval ( ( ) => updateVoteEndTime ( ) , 1000 ) ;
281+ updateVoteEndTime ( ) ;
282+ }
283+
284+ function updateVoteEndTime ( ) {
285+ voteTimer -- ;
286+ elements . voteTimeText . innerText = TheI18n . GetString ( I18nStringKey . kVM_VoteForResetTimer , voteTimer ) ;
287+ if ( voteTimer === 0 ) clearInterval ( voteInterval ) ;
288+ }
289+
290+ function voteEnd ( ) {
291+ clearInterval ( voteInterval ) ;
292+ elements . voteResetPanel . style . display = 'none' ;
293+ }
294+
295+ function turnIntervalCb ( ) {
296+ turnTimer -- ;
297+ setTurnStatus ( ) ;
298+ }
0 commit comments